写点什么

Java 多线程 —— 同步代码块,给大家安排上

用户头像
极客good
关注
发布于: 刚刚
  1. 必须有两个或两个以上的线程

  2. 同一时间只有一个线程能够执行同步代码块

  3. 多个线程想要同步时,必须共用同一把锁


synchronized(对象)括号里面的对象就是一把锁


使用 synchronized 的过程:


  1. 只有抢到锁的线程才可以执行同步


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


代码块,其余的线程即使抢到了 CPU 执行权,也只能等待,等待锁的释放。


  1. 代码执行完毕或者程序抛出异常都会释放锁,然后还未执行同步代码块的线程争抢锁,谁抢到谁就能运行同步代码块。

[](

)同步代码块


因此,修改后的代码为:


package test.MyThread.ticketDemo;


public class RunnableThread implements Runnable{


private int ticket = 100;


Object obj = new Object();


@Override


public void run(){


while(true){


synchronized (obj) {


if (ticket > 0) {


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


System.out.println(Thread.currentThread().getName() + "正在出售第 " + ticket + " 张票");


ticket--;


}


}


}


}


}


package test.MyThread.ticketDemo;


public class ticketDemo1 {


public static void main(String[] args) {


//这里没有改动,只是在上一个代码中加了一把锁


RunnableThread r1 = new RunnableThread();


Thread t1 = new Thread(r1,"窗口一");


Thread t2 = new Thread(r1,"窗口二");


Thread t3 = new Thread(r1,"窗口三");


t1.start();


t2.start();


t3.start();


}


}



可以看出来结果符合我们的预期,是正确的


现在又有了新的问题,那就是如果我在构造线程的 RunnableThread 类里面加入方法呢?同步代码块里面出现方法时,我们应该怎么“上锁”呢?

[](

)同步方法(this 锁)

[](

)同步方法,在 public 的后面加上 synchronized 关键字


package test.MyThread.ticketDemo;


public class RunnableThread1 implements Runnable{


private int ticket = 100;


Object obj = new Object();


public boolean flag = true;


@Override


public void run(){


if(flag==true){


while(ticket>0){


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


SellTicket1();


}


}


}


//同步方法,在 public 的后面加上 synchronized 关键字


public synchronized void SellTicket1(){


if(ticket>0){


System.out.println(Thread.currentThread().getName()+"正在出售第 "+ticket+" 张票");


ticket--;


}


}


}


package test.MyThread.ticketDemo;


public class ticketDemo2 {


public static void main(String[] args) throws InterruptedException {


RunnableThread1 r = new RunnableThread1();


Thread t1 = new Thread(r,"窗口一");


Thread t2 = new Thread(r,"窗口二");


t1.start();


t2.start();


}


}

[](

)this 锁


先来看看,如果有两条路径,一条路径是使用同步代码块,但是对象是 obj,另一条路径是使用同步方法


package test.MyThread.ticketDemo;


public class TicketWindow2 implements Runnable{


//定义 100 张票


private static int tickets = 100;


Object obj = new Object();


int i =0;


@Override


public void run() {


while (true){


if(i%2==0){


synchronized (obj){


if(tickets>0){


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票");


}


}


}else {


sellTicket();


}


i++;


}


}


public synchronized void sellTicket(){


if(tickets>0){


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票");


}


}


}



结果出错,说明同步方法的用的对象锁不能是任意的对象,不同的线程应该用相同的锁。同步方法是属于对象,而在这个类里面调用方法的是 this 对象,也就是 this.sellTicket(),因此把 this 提取出来作为对象锁中的对象。这样多个线程都用的是 this 锁


package test.MyThread.ticketDemo;


public class TicketWindow2 implements Runnable{


//定义 100 张票


private static int tickets = 100;


Object obj = new Object();


int i =0;


@Override


public void run() {


while (true){


if(i%2==0){


synchronized (this){


if(tickets>0){


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票");


}


}


}else {


sellTicket();


}


i++;


}


}


public synchronized void sellTicket(){


if(tickets>0){


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票");


}


}


}


修改完成后再运行代码,发现没有错误


注:


  1. 一个线程使用同步方法,另一个线程使用同步代码块 this 锁,可以实现同步

  2. 一个线程使用同步方法,另一个线程使用同步代码块,但是不是 this 锁。这种情况不能实现同步。

[](

)静态同步方法


同步方法的锁对象是 this,


静态同步方法的锁对象是:这个静态同步方法所属的类的字节码文件


下面代码挺长的,但其实就修改了上面同步方法的代码的两处地方


  1. public synchronized void sellTicket(){}改为


public synchronized static void sellTicket(){}


  1. synchronized (this){}改为 synchronized (TicketWindow2.class){}


package test.MyThread.ticketDemo;


public class TicketWindow2 implements Runnable{


//定义 100 张票


private static int tickets = 100;


Object obj = new Object();


int i =0;


@Override


public void run() {


while (true){


if(i%2==0){


synchronized (TicketWindow2.class){


if(tickets>0){


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票");


}


}


}else {


sellTicket();


}


i++;


}


}


public synchronized static void sellTicket(){


if(tickets>0){


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


System.out.println(Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票");


}


}


}


main()方法里面创建进程和启动进程的代码,和上面同步方法里面的代码相同


结果也和上面的一样,都不再列出来了

[](

)死锁问题


package test.MyThread.ticketDemo;


//两个不同的锁对象


public class LockObject {


public static final Object lock1 = new Object();


public static final Object lock2 = new Object();


}


package test.MyThread.ticketDemo;


public class DieLockThread extends Thread{


public boolean flag;


public DieLockThread(boolean flag){

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Java 多线程 —— 同步代码块,给大家安排上