本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、同步方法_synchronized 关键字
同步代码块可以有效解决线程的安全问题,当把共享资源的操作放在 synchronized 定义的区域内时,便为这些操作加了同步锁。
在方法前面同样可以使用 synchronized 关键字来修饰,被修饰的方法为同步方法,它能实现和同步代码块同样的功能,具体语法格式如下:
synchronized 返回值类型 方法名([参数1,……]){}
被 synchronized 修饰的方法在某一时刻只允许一个线程访问,访问该方法的其他线程都会发生阻塞,直到当前线程访问完毕后,其他线程才有机会执行方法。
ExampleM13:
//同步方法
//定义 Ticket2 类实现 Runnable 接口
class Ticket2 implements Runnable {
private int tickets = 10;
public void run() {
while (true) {
saleTicket(); //调用售票方法
if (tickets <= 0) {
break;
}
}
}
//定义一个同步方法 saleTicket()
private synchronized void saleTicket() {
if (tickets>0) {
try {
Thread.sleep(10); //经过的线程休眠 10 毫秒
} catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---卖出的票"+tickets--);
}
}
}
public class ExampleM13 {
public static void main(String[] args) {
Ticket2 ticket = new Ticket2(); //创建 Ticket1对象
//创建并开启四个线程
new Thread(ticket,"线程一").start();
new Thread(ticket,"线程二").start();
new Thread(ticket,"线程三").start();
new Thread(ticket,"线程四").start();
}
将售票代码抽取为售票方法 saleTicket (),并用 synchronized 关键字把 saleTicket()修饰为同步方法,然后在 run ()方法中调用该方法。
二、死锁问题_两个线程都需要对方所占用的锁
ExampleM14:
//死锁问题
class DeadLockThread implements Runnable {
static Object chopsticks = new Object(); //定义 Object类型的 chopsticks(筷子)锁对象
static Object knifeAndFork = new Object(); //定义 Object类型的 knifeAndFork(刀叉)锁对象
private boolean flag; //定义 Boolean 类型的变量 flag
DeadLockThread(boolean flag) { //定义有参的构造方法
this.flag = flag;
}
public void run() {
if (flag) {
while (true) {
synchronized (chopsticks) { //chopsticks 锁对象上的同步代码块
System.out.println(Thread.currentThread().getName()+"---if---chopsticks");
synchronized (knifeAndFork) { //knifeAndFork 锁对象上的同步代码块
System.out.println(Thread.currentThread().getName()+"---if---knifeAndFork");
}
}
}
}else {
while (true) {
synchronized (knifeAndFork) { //knifeAndFork 锁对象上的同步代码块
System.out.println(Thread.currentThread().getName()+"---else---knifeAnfFork");
synchronized (chopsticks) { //chopsticks 锁对象上的同步代码块
System.out.println(Thread.currentThread().getName()+"---else---chopsticks");
}
}
}
}
}
}
public class ExampleM14 {
public static void main(String[] args) {
//创建两个 DeadLockThread对象
DeadLockThread d1 = new DeadLockThread(true);
DeadLockThread d2 = new DeadLockThread(false);
//创建并开启两个线程
new Thread(d1,"Chinese").start(); //创建开启线程 Chinese
new Thread(d2,"American").start(); //创建开启线程 American
}
}
创建了 Chinese 和 American 两个线程,分别执行 run ()方法中 if 和 else 代码块中的同步代码块。 Chinese 线程中拥有 chopsticks 锁,只有获得 knifeAndFork 锁才能执行完毕,而 American 线程拥有 knifeAndFork 锁,只有获得 chopsticks 锁才能执行完毕,两个线程都需要对方所占用的锁,但是都无法释放自己所拥有的锁,于是这两个线程都处于了挂起状态,从而造成了死锁。