写点什么

Java 多线程 —— 同步代码块 (1),狂神说 docker 进阶笔记

用户头像
极客good
关注
发布于: 刚刚

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--)+" 张票");


}


}


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


}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){


this.flag = flag;


}


@Override


public void run() {


if(flag){


synchronized(LockObject.lock1){


System.out.println("lock1");


synchronized(LockObject.lock2){


System.out.println("lock2");


}


}


}else{


synchronized(LockObject.lock2){


System.out.println("lock2");


synchronized(LockObject.lock1){


System.out.println("lock1");


}


}


}


}


}


package test.MyThread.ticketDemo;


public class DieLockDemo {


public static void main(String[] args) {


DieLockThread d1 = new DieLockThread(true);


DieLockThread d2 = new DieLockThread(false);


d1.start();


d2.start();


}


}



程序会卡在这一步,不能进行下一步也不能停止


利用有参构造,构造出来的线程 d1 应该是先获得锁对象 LockObject.lock1 然后执行打印语句。接着获取锁对象 LockObject.lock2,然后打印 lock2。


但是这里因为线程 d2 是先获取的锁对象 LockObject.lock2,并占据这个锁对象,然后想获得锁对象 LockObject.lock1,但 LockObject.lock1 此时被线程 d1 占据着


两个线程都在等待对方释放锁对象,然后进行下一步,但是两者都不释放,导致程序卡死在这里。这就造成了死锁。

lock

package test.MyThread.ticketDemo;


import java.util.concurrent.locks.Lock;


import java.util.concurrent.locks.ReentrantLock;


public class LockThread implements Runnable{


private int ticket = 100;


Lock lock = new ReentrantLock();


@Override


public void run(){


while(ticket>0){


try{


lock.lock();


if(ticket>0){


try {


Thread.sleep(100);


} catch (InterruptedException e) {


e.printStackTrace();


}


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


}


}finally {


lock.unlock();


}


}


}


}

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Java 多线程 —— 同步代码块(1),狂神说docker进阶笔记