码迷,mamicode.com
首页 > 编程语言 > 详细

跟着刚哥梳理java知识点——多线程(十六)

时间:2017-04-18 23:02:29      阅读:249      评论:0      收藏:0      [点我收藏+]

标签:str   线程   min   守护   接口实现   override   extends   private   for   

创建多线程
第一种方式
① 继承:继承Thread。
② 重写:重写Thread类的run()方法
③ 创建:创建一个子类的对象
④ 调用:调用线程的start()方法,启动此线程,调用run()方法

 1 class Work extends Thread{ //① 继承
 2   @Override
 3   //② 重写
 4   public void run() {
 5     for (int i = 1 ;i < 5; i++) {
 6       System.out.println(Thread.currentThread().getName()+":"+i);
 7     }
 8   }
 9 }
10 public static void main(String[] args) {
11   //③ 创建
12   Work work = new Work();
13   //④ 调用
14   work.start();
15   for (int i = 1 ;i < 5; i++) {
16     System.out.println(Thread.currentThread().getName()+":"+i);
17   }
18 }

输出结果:

main:1
main:2
main:3
main:4
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4

思考:把上面的start修改成run,想想会有什么结果呢?

main:1
main:2
main:3
main:4
main:1
main:2
main:3
main:4

走了两遍的main。因为Start是启动线程,run只是正常的调用了一下方法,和多线程没关系。


第二种方法
① 实现接口:实现Runnable接口的类
② 实现抽象方法:实现接口的run的方法
③ 创建对象:创建一个Runnable接口实现类的对象
④ 放入构造器:将此对象作为形参传递给Thread的构造器,创建Thread对象
⑤ 启动线程:启动这个线程

 1 class Work implements Runnable{ //① 实现接口
 2   //② 实现抽象方法
 3   public void run() {
 4     for (int i = 11 ;i < 100; i++) {
 5       System.out.println(Thread.currentThread().getName()+":"+i);
 6     }
 7   }
 8 }
 9 
10 public static void main(String[] args) {
11   //③ 创建对象
12   Work work = new Work();
13   //④ 放入构造器
14   Thread t1 = new Thread(work);
15   //⑤ 启动线程
16   t1.start();
17   for (int i = 11 ;i < 100; i++) {
18     System.out.println(Thread.currentThread().getName()+":"+i);
19   }
20 }

 

Thread(类) VS Runnable(接口)
① Runnable避免了java类的单继承局限性,接口可以多继承。
② 如果多个线程操作同一份资源更适合使用Runnable的方式


线程Thread的常用方法:
① start():启动线程并执行相应的run()方法
② run():将子线程要执行的代码放入run()方法
③ currentThread():静态的,调取当前的线程
    √ getName():获取此线程的名字
   例如:Thread.currentThread().getName()

    √ setName():设置线程的名字

④ yield():强制释放当前cpu执行权,(例如子线程和主线程都循环输出100次的数字,当主线程%10==0的时候,就调用主线程yield方法Thread.currentThread().yield(),强制主线程释放CPU执行权)需要说明的是释放线程的CPU执行权不代表其他线程就一定能抢到CPU的执行权。也可能释放的线程再次抢到资源。
⑤ join():在A线程中调用B线程join(参与进来的意思)方法,表示当执行到此方法,A线程停止执行,B执行完毕后,A再执行。
⑥ sleep():显式的让当前线程睡眠1毫秒

设置线程的优先级:优先级高只能说明抢到的几率高,不代表一定先完成
① getPriority():获取线程的优先级
② setPriority():设置线程的优先级
一共是10个等级.默认是等级5,Thread里的属性就是等级级别
Thread属性:
√ MAX_PRIORITY:最高的线程优先级
√ MIN_PRIORITY:最低的线程优先级
√ NORM_PRIORITY:默认的线程优先级
线程分为两类
①守护线程
   用来服务用户的,垃圾回收就是一个典型的守护线程
   若JVM都是守护线程,当前JVM将退出
②用户线程
   用户自己创建的线程
   用户线程-->守护线程: 
   通过在start()方法前调用thread.setDaemon(True)就可以

线程的生命周期:枚举status代表了状态

技术分享

1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
   (一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
   (二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
   (三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程安全性
原因:
由于一个线程在操作共享数据过程中未执行完的情况下,另外的线程参与进来,
导致共享数据存在安全问题。
共享数据:多个线程共共同操作同一个数据(变量)

解决:
必须让一个线程操作共享数据完毕之后,其他线程才有机会共享数据的操作

java如何解决的呢?
方式一:同步代码块
synchronized(同步监视器){
//需要同步的代码
}
同步块包住谁呢?谁操作共享数据就包谁
注意:在实现的方式中,可以使用this充当锁,但是在继承的方式中,慎用this

方式二:同步方法
同步方法的锁:this

public synchronize void 方法(){

}

单例模式:线程安全

 1 class Singleton{
 2   private Singleton(){
 3   
 4   }
 5   private static Singleton instance = null;
 6   public static Singleton getInstance(){
 7   if(instance == null){
 8     synchronize(Singleton.calss){
 9       if(instance == null){
10         instance = new Singleton();
11       }
12     }
13   }
14   return instance;
15 } 

 

面试题:
银行有一个账号,有两个储户分别向一个账户存入3000元,每次存1000,存3次
,每次存完后打印账户余额

分析:
共享资源是什么?显然是一个账号。
是否需要用多线程?显然是用的,因为有两个储户

 1 class Account {
 2   double balance = 0;
 3   public synchronized void cunqian(double crm){
 4     balance += crm;
 5     System.out.println(Thread.currentThread().getName() + ":" + balance);
 6   }
 7 }
 8 class Customer implements Runnable{
 9   Account account;
10   public Customer(Account account) {
11     this.account = account;
12   }
13   @Override
14   public void run() {
15     for (int i = 0; i < 3; i++) {
16       account.cunqian(1000);
17     }
18   }
19 }
20 public static void main(String[] args) throws Exception {
21   Account account = new Account();
22   Customer customer = new Customer(account);
23   Thread t1 = new Thread(customer);
24   t1.start();
25   Thread t2 = new Thread(customer);
26   t2.start();
27   t1.setName("储户1");
28   t2.setName("储户2");
29 }

上面代码需要需要的是:由于是两个类,一定要保证共享资源类千万不要被多次实例化
所以一定要让第一个类实例化完成后当成形参出入到第二个中构造(看红色标记部分)


线程通信:
① wait():令当前线程挂起并放弃CPU、同步资源。让别的线程可访问并修改共享资源,而当前前程排队等候再次对资源的访问
② notify():唤醒正在排队等候同步资源的线程中优先级最高的锁
③ notifyAll();唤醒所有正在排队的等待的所有线程结束等待

跟着刚哥梳理java知识点——多线程(十六)

标签:str   线程   min   守护   接口实现   override   extends   private   for   

原文地址:http://www.cnblogs.com/hzg110/p/6707025.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!