0
点赞
收藏
分享

微信扫一扫

Java28- 线程同步[继承Thread,实现Runnable]


线程同步

文章目录

  • ​​线程同步​​
  • ​​实现Runnable的好处​​
  • ​​继承Thread: 中的线程同步​​
  • ​​方法一: synchronized (object){}​​
  • ​​方法二:synchronized 给方法​​
  • ​​实现Runnable:线程同步方法​​
  • ​​方法一: synchronized (object){}​​
  • ​​方法二:synchronized 给方法​​

并发与并行

  • 并行:多个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();
}
}

结果:线程同步成功


举报

相关推荐

0 条评论