一、没用锁之前出现的问题
package day34_thread_线程.线程锁; /* * t1,t2,t3 * 假设只剩一张票 * t1过来了,他一看有票,他就进来了,但是他突然肚子不舒服,然后他就去上卫生间了 * t2也过来了,他一看也有票,他也进来了,但是他的肚子也不舒服,他也去上卫生间了 * * t1上完了卫生间回来了,开始售票 * tickets = 0; * t2也上完卫生间回来了,他也进行售票 * tickets = -1; * * */ public class SleepThread implements Runnable { int nums = 20; @Override public void run() { // if(num > 0) { // for(int i=0;i<100;i++) { // System.out.println(Thread.currentThread().getName() + ":" + i); // } while(true) { if(nums > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":" + nums--); }else { System.exit(0); } } } }
package day34_thread_线程.线程锁; /* * 模拟火车站售票 * * 分析: * 首相需要有火车票的总数量,每售出一张则数量减一 * 当火车票的数量小于1的时候,停止售票 * 使用多线程模拟多个窗口进行售票 * 当火车票全部售完,火车站也一样敞开大门欢迎我们 * * static void sleep(long millis) : 让当前线程睡一会 */ public class SleepDemo { public static void main(String[] args) { SleepThread st = new SleepThread(); Thread t = new Thread(st); t.setName("窗口1"); t.start(); Thread t1 = new Thread(st); t1.setName("窗口2"); t1.start(); Thread t2 = new Thread(st); t2.setName("窗口3"); t2.start(); } }
输出:会出现票的争夺,
二、使用线程锁解决
synchronized是java中的一个关键字,修饰符。
synchronized:同步(锁),可以修饰代码块和方法,被修饰的代码块和方法一旦被某个线程访问,则直接锁住,其他的线程将无法访问
同步代码块:
synchronized(锁对象){
}
同步方法:
public synchronized void method() {
}
synchronized代码块又分为这么几种:synchronized(this),synchronized(className.class)和synchronized(Object obj)
* synchronized(this):修饰非静态方法,锁都在当前对象,只限制当前对象对该代码块的同步。
* synchronized(className.class 字节码对象):修饰静态方法,锁在类而不在类对象,只要是className类对象访问该代码块都被要求同步。
* synchronized(Object obj) :这时锁就是对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁
1. 代码块
package day34_thread_线程.线程锁; public class SynchronizedThtread implements Runnable { //火车票数 20 int num = 20; Object obj = new Object(); @Override public void run() { while(true) { synchronized(obj) { try{Thread.sleep(100); }catch (InterruptedException e) { e.printStackTrace(); } if(num > 0) { System.out.println(Thread.currentThread().getName() + ":" + num--); } } } } }
public class SynDemo { public static void main(String[] args) { SynchronizedThtread st = new SynchronizedThtread(); Thread t = new Thread(st); t.setName("窗口1"); t.start(); Thread t1 = new Thread(st); t1.setName("窗口2"); t1.start(); Thread t2 = new Thread(st); t2.setName("窗口3"); t2.start(); } }
输出:
线程切换,但是票数按顺序减少,符合要求
2.静态方法、非静态方法
package day34_thread_线程.线程锁; public class SynFunThread implements Runnable { /*static int num = 100;*/ int num = 20; @Override public void run() { method(); } private synchronized void method() { while(true) { if(num > 0) { try{Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":" + num--); } } } /* private static synchronized void method() { while(true) { if(num > 0) { try{Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":" + num--); } } }*/ }
public class SynFunDemo { public static void main(String[] args) { SynFunThread sft = new SynFunThread(); Thread t = new Thread(sft); Thread t1 = new Thread(sft); Thread t2 = new Thread(sft); t.start(); t1.start(); t2.start(); } }
输出:
来源:https://www.cnblogs.com/longesang/p/11340919.html