线程安全方式一: 同步代码块
- 同步代码块关键字: synchronized(同步锁) {}
- 将要同步的代码放在synchronized中
- 任意一个对象充当同步锁 Runnble接口中可以考虑使用tihs充当同步锁
- 多个线程必须使用统一个同步锁
缺点: 代码效率慢 代码内容只能有一个线程执行 相当于单线程 ```java /**
- 创建人:LYY
- 创建时间:2022/4/26
同步代码块解决线程安全问题 */ public class SynchronizedTest {
public static void main(String[] args) { TicketOne ticketOne = new TicketOne(); // 创建线程一 Thread t1 = new Thread(ticketOne); t1.setName(“线程一:”); Thread t2 = new Thread(ticketOne); t2.setName(“线程二:”); Thread t3 = new Thread(ticketOne); t3.setName(“线程三:”); t3.setPriority(10); t2.start(); t1.start(); t3.start(); }
}
class TicketOne implements Runnable{
private int count = 100;
Demo demo = new Demo();
@Override
public void run() {
while (true) {
// 同步代码块
synchronized(demo){
// 2. 将要执行的操作 卸载run方法中
if (count>0){
System.out.println(Thread.currentThread().getName()+ "count = "+count);
} else if (count == 0){
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
// 放弃当前线程权
Thread.yield();
}
}
}
}
```java
/**
* 创建人:LYY
* 创建时间:2022/4/26
* 模拟售票
* 同100张车票 同时多个线程抢票
* 每个线程执行一次 当前票数减一
*/
// 1. 实现Runnable接口
public class Ticket implements Runnable{
private int count = 100;
@Override
public void run() {
// 2. 将要执行的操作 卸载run方法中
while (true) {
// 同步锁
synchronized(Ticket.class){
if (count > 0) {
System.out.println(Thread.currentThread().getName()+ "count = "+count);
} else if (count == 0) {
break;
}
count--;
}
}
}
}
class TicketTest{
@Test
public void ticketTest() {
// 3. 创建Runnable接口实现类的对象
Ticket ticket = new Ticket();
// 4. 将Runnable接口实现类的对象作为参数 传递给Thread对象 创建线程
// 创建线程1
Thread t1 = new Thread(ticket);
t1.setName("线程一:");
// 创建线程2
Thread t2 = new Thread(ticket);
t2.setName("线程二:");
// 创建线程3
Thread t3 = new Thread(ticket);
t3.setName("线程三:");
t3.start();
t1.start();
t2.start();
}
}
二、线程安全方式二:同步方法
- 创建一个方法 方法修饰符后添加synchronized关键字
- 将要执行(同步)的操作写在synchronized方法中
- run方法中调用synchronized方法
- synchronized方法依然存在同步锁 该对象为隐式的
- 继承Thread类中的同步方法需要声明为静态的 该同步方法同步锁隐式的 具体为class(.getClassz)
实现Runnable接口中的同步方法只需要添加synchronized 该方法的同步锁为隐式的 具体为this ```java /**
- 创建人:LYY
- 创建时间:2022/4/26
使用同步方法解决继承Thread类的线程安全问题 */ public class ThreadTwo extends Thread{
private static int count = 100; static boolean isOk = true;
@Override public void run() { while (isOk) {
show();
} }
/**
- 同步方法 隐式的同步锁
同步锁对象为class */ public static synchronized void show() {
if (count > 0) {
System.out.println(Thread.currentThread().getName() + count);
count--;
} else if (count == 0) {
isOk = false;
} } }
class ThreadTwoTest{ public static void main(String[] args) { ThreadTwo t1 = new ThreadTwo(); ThreadTwo t2 = new ThreadTwo(); ThreadTwo t3 = new ThreadTwo(); t3.setName(“线程三:”); t1.setName(“线程一:”); t2.setName(“线程二:”); t1.start(); t2.start(); t3.start(); } }
```java
/**
* 创建人:LYY
* 创建时间:2022/4/26
* 使用同步方法解决继承Thread类的线程安全问题
*/
public class ThreadTwo extends Thread{
private static int count = 100;
static boolean isOk = true;
@Override
public void run() {
while (isOk) {
show();
}
}
/**
* 同步方法 隐式的同步锁
* 同步锁对象为class
*/
public static synchronized void show() {
if (count > 0) {
System.out.println(Thread.currentThread().getName() + count);
count--;
} else if (count == 0) {
isOk = false;
}
}
}
class ThreadTwoTest{
public static void main(String[] args) {
ThreadTwo t1 = new ThreadTwo();
ThreadTwo t2 = new ThreadTwo();
ThreadTwo t3 = new ThreadTwo();
t3.setName("线程三:");
t1.setName("线程一:");
t2.setName("线程二:");
t1.start();
t2.start();
t3.start();
}
}
三、Lock锁解决线程安全问题
- 实现线程接口(Runnable)或类(Thread)
- 在线程类中创建Lock子类ReentrantLock对象
- 在需要同步数据前 手动使用ReentrantLock对象调用锁(lock)方法
- 同步数据操作接收 手动使用renntrantLock对象调用解锁(unlock)方法
```java
/**
- 创建人:LYY
- 创建时间:2022/4/27
- 使用同步锁解决线程安全问题
- 同步锁使用ReentrantLock类
- 在线程类中声明Lock的实现类对象 ReentrantLock
- 在需要同步的操作前 手动声明锁
- 在同步操作后 手动解锁 */ public class LockTest { }
class TicketTwo implements Runnable{
private int count = 100;
// 同步锁
ReentrantLock reentrantLock = new ReentrantLock(true);
@Override
public void run() {
while (true) {
try {
// 调用锁定方法
reentrantLock.lock();
if (count > 0) {
System.out.println(Thread.currentThread().getName() + count);
} else {
break;
}
count--;
} finally {
// 调用解锁方法
reentrantLock.unlock();
}
}
}
}
```java
/**
* 创建人:LYY
* 创建时间:2022/4/27
*/
public class Client implements Runnable{
private int count;
/**
* 同步锁对象
*/
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 3; i++) {
deposit();
}
}
/**\
* 存钱方法
* 固定存款1000元
*/
public void deposit() {
try {
// 同步锁锁定
lock.lock();
count +=1000;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "存款成功! 余额:" + count);
} finally {
// 释放同步锁
lock.unlock();
}
}
}
class ClientTest{
public static void main(String[] args) {
// 创建对象
Client c = new Client();
// 创建客户A(线程A)
Thread thread1 = new Thread(c);
Thread thread2 = new Thread(c);
thread1.setName("线程A:");
thread2.setName("线程B:");
thread1.start();
thread2.start();
}
}