Java初学总结(二十五)

tech2025-04-30  7

资源共享

1.继承Thread类所创建的线程不能实现资源共享功能

public class MyThread extends Thread{ //定义车票【共享资源】 private int piao=5; @Override public void run() { while(piao>0) { //我们通过线程的暂停来模拟 //收钱-->打票-->找钱 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+ "--卖出1张票,还剩"+(--piao)+"张"); } } } package com.wangxing.test1; public class TestMain1 { public static void main(String[] args) { MyThread th1=new MyThread(); MyThread th2=new MyThread(); MyThread th3=new MyThread(); th1.setName("窗口1"); th2.setName("窗口2"); th3.setName("窗口3"); th1.start(); th2.start(); th3.start(); } }

2.通过实现Runnable接口所创建的线程可以实现资源共享功能。

package com.wangxing.test2; public class MyThread implements Runnable{ //定义车票【共享资源】 private int piao=5; @Override public void run() { while(piao>0) { //我们通过线程的暂停来模拟 //收钱-->打票-->找钱 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+ "--卖出1张票,还剩"+(--piao)+"张"); } } } package com.wangxing.test2; public class TestMain2 { public static void main(String[] args) { //创建目标对象 MyThread mth=new MyThread(); //创建线程对象 Thread th1=new Thread(mth); Thread th2=new Thread(mth); Thread th3=new Thread(mth); //设置线程名称 th1.setName("窗口1"); th2.setName("窗口2"); th3.setName("窗口3"); //开启线程 th1.start(); th2.start(); th3.start(); } }

通过上面的实现Runnable接口的买票程序可以实现资源共享,但是卖出会卖出剩下负数的情况。当多条线程,同时访问同一个资源的时候,会产生数据不一致的错误情况。

3.为什么需要线程同步/线程安全? 因为当多条线程,同时访问同一个资源的时候,会产生数据不一致的错误情况。为了解决这种数据不一致的错误情况,我们才学习线程同步。

4.什么是线程同步/线程安全? 当多条线程同时访问同一个资源的时候,每一次只能由的其中一条线程访问公共资源,其他的线程都处于等待状态,当这一条线程访问完后,其他线程中的一条才能访问,剩下的线程继续等待当前线程访问结束,实现这个过程就是线程同步。

5.线程同步/线程安全的实现方式有几种,分别是什么,有什么区别?

(1)同步代码块 格式: synchronized(同步对象){ }

package com.wangxing.test3; public class MyThread implements Runnable{ //定义车票【共享资源】 private int piao=5; @Override public void run() { //同步代码块 synchronized (this) { while(piao>0) { //我们通过线程的暂停来模拟 //收钱-->打票-->找钱 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+ "--卖出1张票,还剩"+(--piao)+"张"); } } } }

同步代码块虽然可以实现买票的效果,但是它在使用的时候,需要设置一个同步对象,由于我们很多时候都不知道这个同步对象应该是谁,容易写错,造成死锁的情况。正是应为这个缺点,我们很少使用同步代码块来实现线程同步。 (2)同步方法 同步方法的定义格式: 访问限制修饰符 synchronized 方法返回值类型 方法名称(){ }

package com.wangxing.test4; public class MyThread implements Runnable{ //定义车票【共享资源】 private int piao=5; private boolean flag=true; @Override public void run() { while(flag) { sellPiao(); } } /** * 买票的同步方法 */ public synchronized void sellPiao() { if(piao>0) { //我们通过线程的暂停来模拟 //收钱-->打票-->找钱 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+ "--卖出1张票,还剩"+(--piao)+"张"); }else { flag=false; } } }

(3)通过Lock接口 Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作 常用的接口方法 由于上面的锁方法是Lock接口,我们要使用就得先创建出Lock接口对象,由于Lock是个接口不能new ,我们就得使用它的子类ReentrantLock来创建对象。

package com.wangxing.test5; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MyThread implements Runnable{ //定义车票【共享资源】 private int piao=5; //创建Lock对象 private Lock lock=new ReentrantLock(); @Override public void run() { lock.lock(); while(piao>0) { //我们通过线程的暂停来模拟 //收钱-->打票-->找钱 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+ "--卖出1张票,还剩"+(--piao)+"张"); } lock.unlock(); } }

最新回复(0)