JAVA——多线程(2)

上一篇多线程

文章摘要
对比继承和实现方法,线程安全与线程同步及其方法

对比继承Thread和实现Runable两种方法

继承Thread

1.java中类是单继承的,如果继承Thread,该类就不能有其他父类了
2.从操作上看,继承方式更简单
3.但无法做到多线程共享同一资源

实现Runable

1.java可实现多接口,该类还可继承其它父类
2.从操作上看,实现方法更复杂,获取线程名称也更复杂(Thread.currentThread())
3.能做到共享同一资源

解释一下共享同一资源
假设我有50个苹果,有A,B,C三个人同时吃苹果
继承:

public class Xianc {
	    public static void main(String[] args) {
	    	 new eatapple("A").start();
			 new eatapple("B").start();
			 new eatapple("C").start();
		}
	}	
class eatapple extends Thread{
	 private int num = 50;
	 public eatapple(String name) {
		 super(name);
	 }
	 public void run() {
		 for(int i = 1;i<=50;i++) {
			 if(num>0) {
			 System.out.println(super.getName()+"吃了"+num--+"个苹果");//获取名称这与实现的不同
			 }
		 }
	 }
}

实现

public class Xianc {
	    public static void main(String[] args) {
	    	 eatapple e = new eatapple();
	    	 new Thread(e,"A").start();
			 new Thread(e,"B").start();
			 new Thread(e,"C").start();
		}
	}	
class eatapple implements Runnable{
	 private int num = 50;
	 
	 public void run() {
		 for(int i = 1;i<=50;i++) {
			 if(num>0) {
				
			 System.out.println(Thread.currentThread().getName()+"吃了"+num--+"个苹果");
			 }
		 }
	 }
}

运行后的继承方法控制台输出的是ABC各吃了50个苹果
而使用实现接口方法,控制台输出的是ABC一共吃了50个苹果

线程同步
线程不安全

当多线程并发的访问同一个资源对象时,可能出现线程不安全的情况
举例:

public class Xianc {
	    public static void main(String[] args) {
	    	 eatapple e = new eatapple();
	    	 new Thread(e,"A").start();
			 new Thread(e,"B").start();
			 new Thread(e,"C").start();
		}
	}	
class eatapple implements Runnable{
	 private int num = 50;
	 
	 public void run() {
		 for(int i = 1;i<=50;i++) {
			 if(num>0) {
			 try {
			 Thread.sleep(10);  //使线程不安全的现象更加明显,并不是sleep()方法导致的线程不安全
			 }catch(InterruptedException e){
			 e.printStackTrace();
			 }
			 System.out.println(Thread.currentThread().getName()+"吃了"+num--+"个苹果");
			 }
		 }
	 }
}

运行后发现:(截取有代表性的一部分)
在这里插入图片描述
发现B和C同时吃了49号和48号的苹果。
原因:上述代码每个线程的操作分为两部分:
1.展示手上拿到的苹果编号
在这里插入图片描述
2.再吃掉苹果(苹果数减一)
在这里插入图片描述
而这两部分未能同步进行。
解决方法:
1.同步代码块:
2.同步方法:
3.锁机制:

同步代码块

格式:

syncronized(同步锁) 
{
   需要同步的代码
}

代码如下:

 public void run() {
		 for(int i = 1;i<=50;i++) {
			 synchronized (this) {
				 if(num>0) {
				 try {
				 Thread.sleep(10);
				 }catch(InterruptedException e){
				 e.printStackTrace();
				 }
				 System.out.println(Thread.currentThread().getName()+"吃了"+num--+"个苹果");
				 }
			 }
		 }
	 }
同步方法

(使用synchronized修饰的方法叫同步方法,保证A线程执行该方法时,其他线程只能在外边等着)
格式:synchronized public void doWork(){ //TODO }
代码如下

 public void run() {                 //不能用synchronized修饰run方法
		 for(int i = 1;i<=50;i++) {
			 eat();
		 }
	 }
	 //定义一个用用synchronized修饰的新方法,并由run方法调用
		 synchronized private void eat() {
			 if(num>0) {
				 try {
				 Thread.sleep(10);
				 }catch(InterruptedException e){
				 e.printStackTrace();
				 }
				 System.out.println(Thread.currentThread().getName()+"吃了"+num--+"个苹果");
				 }
			 }
	 }
	 	

同步锁:
对于非static方法,同步锁是this;
对于static方法,同步锁是当前方法所在的字节码对象(Apple2.class)

使用synchronized的利弊:
好处:保证了多线程并发访问的同步操作,避免了线程的安全性问题
缺点:用synchronized修饰的代码块性能低
建议:尽量减少synchronized的作用域

锁机制

Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,上述两种方法具有的功能Lock都有,并更加强大,更能体现面向对象思想
格式:

class X{
	private final ReentrantLock lock = new ReentrantLock();
	//......
	public void m(){                  //m是需要同步的方法
		lock.lock();                  //实例(第一个lock)调用lock()方法
		try{
		}catch(){
		}finally{
			lock.unlock();             //必须要有的步骤,关闭锁!
		}
	}
}

代码如下

public class Xianc {
    public static void main(String[] args) {
		eatapple e = new eatapple();	
		new Thread(e,"小A").start();
		new Thread(e,"小B").start();
		new Thread(e,"小C").start();                     //通过实例化eatapple创建三个线程
	    }
}
class eatapple implements Runnable{
	 private int num = 50;                                //苹果数量
	 private final Lock l = new ReentrantLock();          //创建一个锁对象
	 public void run() {
		 for(int i = 1;i<=50;i++) {
			 eat();
	}
}
	 private void eat() {
		 l.lock();
			 try {
				 if(num>0) {
				 System.out.println(Thread.currentThread().getName()+"吃了"+num+"个苹果");
				 Thread.sleep(10);
				 num--;
				 }
			 }catch(InterruptedException e){
				 e.printStackTrace();
			 }finally {
				 l.unlock();
		 }	
	 }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值