线程同步
文章目录
并发与并行
- 并行:多个CPU同时执行多个任务, 比如: 多个人同时做不同的事
- 并发: 一个CPU(采用时间片)同时执行多个任务,比如: 秒杀,多个人做同一件事
线程同步:
- 多个线程同时读写同一份共享资源,可能会引起从图,所以引入线程"同步"机制,即各线程要有先来后到
同步就是排队+锁:
- 几个线程之间要排队,一个个对共享资源操作,而不是同时进行操作
- 为了保证数据在方法中被访问的正确性,在访问时加入锁机制
模拟卖票
两个窗口分别售票,票数为10张
分别使用继承Thread和实现Runnable两种方式实现
继承Thread: 线程代码存放Thread子类run方法中。
实现Runnable:线程代码存在接口的子类的run方法
实现Runnable的好处
1)避免了单继承的局限性
2)多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源
确保一个时间点只有一个线程访问共享资源,可以给共享资源加一把锁,这把锁只有一把钥匙,哪个线程获取了这把钥匙,才有权利范文该共享资源
在java 代码中实现同步
使用synchronized(同步监视器)关键字同步方法或代码块。
synchronized (同步监视器){
// 需要被同步的代码;
}
synchronized还可以放在方法声明中,表示整个方法,为同步方法。
例如:
public synchronized void show (String name){
// 需要被同步的代码;
}
同步监视器
- 同步监视器可以是任何对象,必须唯一,保证多个线程获得是同一个对象(锁).
同步监视器的执行过程
1.第一个线程访问,锁定同步监视器,执行其中代码.
2.第二个线程访问,发现同步监视器被锁定,无法访问.
3.第一个线程访问完毕,解锁同步监视器.
4.第二个线程访问,发现同步监视器没有锁,然后锁定并访问.
注:一个线程持有锁会导致其他所有需要此锁的线程挂起;在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题.
继承Thread: 中的线程同步
方法一: synchronized (object){}
结果:线程同步成功
TicketThread
//最核心的 操作代码块
//object 唯一的一把钥匙
// 哪一个线程得到了钥匙 就可以进入同步代码块
// 一次只能进一个
synchronized (object) {//synchronized表示锁 object表示钥匙
}
public class TicketThread extends Thread {
static int num = 10;
static Object object = new Object();
@Override
public void run() {
// /一直出票,num=0出票结束
while (true) {
//最核心的 操作代码块
//object 唯一的一把钥匙
// 哪一个线程得到了钥匙 就可以进入同步代码块
// 一次只能进一个
synchronized (object) {//synchronized表示锁 object表示钥匙
if (num > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出票:" + num);//t1=10 失去执行权1
num--;
} else {
break;
}
}
}
}
}
测试
public class Test {
public static void main(String[] args) {
//出票的任务,只有一个对象
TicketThread t1 = new TicketThread();
t1.setName("a");
t1.start();
TicketThread t2 = new TicketThread();
t2.setName("b");
t2.start();
}
}
结果:线程同步成功
方法二:synchronized 给方法
结果:线程同步失败
-
synchronized 给方法枷锁 钥匙是this 有多个线程对象 就有多把钥匙
-
public synchronized void printTick() {}
-
测试部分创建多个对象,进行多线程
-
TicketThread t1 = new TicketThread(); t1.setName("a"); t1.start(); TicketThread t2 = new TicketThread(); t2.setName("b"); t2.start();
TicketThread
public class TicketThread extends Thread {
static int num = 10;
@Override
public void run() {
//
while (true) {
if (num == 0) {
break;
}
printTick();
}
}
/*
不可以 加锁失效
*/
//synchronized 给方法枷锁 钥匙是this 有多个线程对象 就有多把钥匙
public synchronized void printTick() {
// 一直出票,num=0出票结束
if (num > 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出票:" + num);//t1=10 失去执行权1
num--;
}
}
}
测试
public class Test {
public static void main(String[] args) {
TicketThread t1 = new TicketThread();
t1.setName("a");
t1.start();
TicketThread t2 = new TicketThread();
t2.setName("b");
t2.start();
}
}
结果:线程同步失败
实现Runnable:线程同步方法
方法一: synchronized (object){}
TicketThread
结果:线程同步成功
- //因为只创建了一个 因此this只有一个
public class TicketThread implements Runnable {
int num = 10;
@Override
public void run() {
// /一直出票,num=0出票结束
while (true) {
//因为只创建了一个 因此this只有一个
synchronized (this) {
if (num > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出票:" + num);//t1=10 失去执行权1
num--;
} else {
break;
}
}
}
}
}
测试
public class Test {
public static void main(String[] args) {
//出票的任务,只有一个对象
TicketThread ticketThread = new TicketThread();
Thread t1 = new Thread(ticketThread,"窗口1");
t1.start();
Thread t2 = new Thread(ticketThread,"窗口2");
t2.start();
}
}
结果:线程同步成功
方法二:synchronized 给方法
结果:线程同步成功
- //synchronized 给方法枷锁 钥匙是this this只创建了一个TicketThread对象
- //所以就this只有一个
TicketThread
public class TicketThread implements Runnable {
int num = 10;
@Override
public void run() {
//
while (true) {
if (num == 0) {
break;
}
printTick();
}
}
//synchronized 给方法枷锁 钥匙是this this只创建了一个TicketThread对象
//所以就this只有一个
public synchronized void printTick() {
// 一直出票,num=0出票结束
if (num > 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出票:" + num);//t1=10 失去执行权1
num--;
}
}
}
测试:
public class Test {
public static void main(String[] args) {
//出票的任务,只有一个对象
TicketThread ticketThread = new TicketThread();
Thread t1 = new Thread(ticketThread,"窗口1");
t1.start();
Thread t2 = new Thread(ticketThread,"窗口2");
t2.start();
}
}
结果:线程同步成功