java多线程—基础入门实例

来源:互联网 发布:windows怎么开发苹果 编辑:程序博客网 时间:2024/06/01 07:20

一)线程基本概念简介

1、操作系统中线程与概念概念

           现在的操作系统是多任务操作系统,多线程是实现多任务的一种方式。


           进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

 

           线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

 

            多进程是指操作系统能同时运行多个任务(程序),“同时”执行是人的感觉,在线程之间实际上轮换执行。多线程是指在同一程序中有多个顺序流在执行。


2、线程的创建与启动

          使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。

 

          一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生死于堆上。

 

            Java中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着。

 

            一个Java应用总是从main()方法开始运行,mian()方法运行在一个线程内,它被称为主线程。

 

          一旦创建一个新的线程,就产生一个新的调用栈。

 

线程总体分两类:用户线程和守候线程。


             当所有用户线程执行完毕的时候,JVM自动关闭。但是守候线程却不独立于JVM,守候线程一般是由操作系统或者用户自己创建的

1】implements Runnabele

package com.xiu.thread.test;/** *eg1:两个线程交替打印 * * @author xiu * @version 2017年8月7日 上午10:21:30  */public class ThreadTest1 {public static void main(String[] args) {// TODO 实例1Runner1 run = new Runner1();//定义实现了Runnable接口的类的对象Thread thread = new Thread(run);//创建线程对象thread.start();//启动线程,相当于启动一个分支调用Runner中的run方法for (int i = 0; i < 15; i++) {System.out.println("main——> "+ i);}System.out.println("结果是交替打印的是不是?因为是一起执行的");}}//实现了Runnable接口。class Runner1 implements Runnable{/** 重写这个run()方法,也就是当用这个类的对象放到Thread的对象中后,用Thread的对象调用start()方法起动线程时,会执行这个方法;*/@Overridepublic void run() {// TODO Auto-generated method stubfor (int i = 0; i < 5; i++) {System.out.println("the test number is :" + i);}}}

package com.xiu.thread.test;/** *eg2:两个线程有序打印 * * @author xiu * @version 2017年8月7日 上午10:21:30  */public class ThreadTest1 {public static void main(String[] args) {Runner1 run = new Runner1();//定义实现了Runnable接口的类的对象run.run();//先执行完run()main方法才继续执行for (int i = 0; i < 5; i++) {System.out.println("main——> "+ i);}System.out.println("结果不是交替打印的是不是?因为先调用了run()后才执行main()方法");}}//实现了Runnable接口。class Runner1 implements Runnable{@Overridepublic void run() {// TODO Auto-generated method stubfor (int i = 0; i < 5; i++) {System.out.println("the test number is :" + i);}}}
2】extends Thread

package com.xiu.thread.test;/** *eg3.继承Thread * * @author xiu * @version 2017年8月7日 上午10:34:42  */public class ThreadTest2 {public static void main(String[] args) {// TODO //Runner2 run = new Runner2();//创建一个继承了Thread的类对象//run.start();//启动线程,相当于启动一个分支调用Runner2中的run方法//run.run();//for (int i = 0; i < 15; i++) {//System.out.println("this is the main: " +i);//}//System.out.println("交叉着打印是不是? 因为他们是同时执行的");Runner2 run = new Runner2();//创建一个继承了Thread的类对象run.run();for (int i = 0; i < 15; i++) {System.out.println("this is the main: " +i);}System.out.println("现在不是交叉着打印是不是? 因为他们是有先后顺序的");System.out.println("注意线程中的start方法只是准备好了一个分支,相当于一个厕所,进来了一个不一定马上就可以上,还要排队");System.out.println("线程基本方法有:");System.out.println("isAlive(),getPriority(),setProprity(),sleep(),join(),yield(),wait(),notify(),notifyAll()");}}class Runner2 extends Thread{public void run() {for (int i = 0; i < 10; i++) {System.out.println("this is the test thread: "+i);}}}


二)线程的创建与启动



三)线程状态的转换


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


四)线程的同步与锁


五)线程的交互wait()、notify()




六)线程的调度与休眠、优先级、让步、合并、存活

1】sleep()

package com.xiu.thread.test;/** *sleep()——这个方法的对象是哪里,就是哪个方法休息。 * @author xiu * @version 2017年8月7日 上午10:45:39  */public class ThreadTestSleep {public static void main(String[] args) {// TODO Auto-generated method stub//Runner3 runner3  = new Runner3();//创建一个继承了Thread的类对象//runner3.start();//启动线程//try {//runner3.sleep(1000);//} catch (Exception e) {//}//runner3.interrupt();//这是唤醒睡眠,也就是停止分支的sleep,使其跑到异常,尽量少用//for (int i = 0; i < 15; i++) {//System.out.println("main test is :" + i);//}//System.out.println("the main is over!");Runner3 runner3  = new Runner3();//创建一个继承了Thread的类对象runner3.start();//启动线程for (int i = 0; i < 3; i++) {System.out.println("main test is :" + i);}System.out.println("the main is over!");runner3.shotDown();//使用这种方式关闭线程比interrupt好很多,减少异常,正如以while()条件判断}}class Runner3 extends Thread{boolean stop = true;public void run() {int i = 0;while(stop){System.out.println("the test num is :" + i);i++;}}public void shotDown() {// TODO Auto-generated method stubstop = false;}}

main test is :0
the test num is :0
the test num is :1
the test num is :2
main test is :1
main test is :2
the test num is :3
the test num is :4
the test num is :5
the test num is :6
the test num is :7
the main is over!
the test num is :8


2】setPriority()


package com.xiu.thread.test;/** *priority线程优先级的提升不能提高确保一定先执行,只能说相对执行时间、机会多一点 * * @author xiu * @version 2017年8月7日 上午11:16:33  */public class ThreadTestPriority {public static void main(String[] args) {Thread run1 = new Thread(new Priority1());//创建一个线程对象,线程中执行priorityThread run2 = new Thread(new Priority2());run1.setPriority(Thread.MAX_PRIORITY);//将run1线程优先级提高3级run1.start();//启动线程,相当于启动一个分支的调用Priority1中run方法run2.run();}}class Priority1 implements Runnable{@Overridepublic void run() {// TODO Auto-generated method stubfor (int i = 0; i < 3; i++) {System.out.println("priority1  is:  " + this.getClass()+ " .  the num is  "  + i);}}}class Priority2 implements Runnable{@Overridepublic void run() {// TODO Auto-generated method stubfor (int i = 0; i < 3; i++) {System.out.println("priority1  is:  " + this.getClass()+ " .  the num is  " + i);}}}
priority  is:  class com.xiu.thread.test.Priority2 .  the num is  0
priority  is:  class com.xiu.thread.test.Priority2 .  the num is  1
priority  is:  class com.xiu.thread.test.Priority1 .  the num is  0
priority  is:  class com.xiu.thread.test.Priority1 .  the num is  1
priority  is:  class com.xiu.thread.test.Priority2 .  the num is  2
priority  is:  class com.xiu.thread.test.Priority1 .  the num is  2


3】yield()

package com.xiu.thread.test;/** *yield()——这是让出一下。也就是执行了这个方法后,这次执行后下次肯定是别的线程。 *不过注意一点,每执行一次只让一次。 * * @author xiu * @version 2017年8月7日 上午11:09:56  */public class ThreadTestYield {public static void main(String[] args) {// TODO Auto-generated method stubRunner5 runner1 = new Runner5();Runner5 runner2 = new Runner5();runner1.start();runner2.start();for (int i = 0; i < 3; i++) {System.out.println("main thread is :" +i);}}}class Runner5 extends Thread{public void run() {for (int i = 0; i < 3; i++) {System.out.println("the yield thread num is :" + i);if (i%2 == 0) {System.out.println("能够被2整除的整数,那就让一让它吧 "+i);yield();}}}}

the yield thread num is :0
the yield thread num is :0
main thread is :0
main thread is :1
main thread is :2
能够被2整除的整数,那就让一让它吧 0
能够被2整除的整数,那就让一让它吧 0
the yield thread num is :1
the yield thread num is :2
能够被2整除的整数,那就让一让它吧 2
the yield thread num is :1
the yield thread num is :2
能够被2整除的整数,那就让一让它吧 2


4】join()

package com.xiu.thread.test;/** * * * @author xiu * @version 2017年8月7日 上午11:02:41  */public class ThreadTestJoin {public static void main(String[] args) {// TODO Auto-generated method stubRunner4 runner4 = new Runner4();runner4.start();try {runner4.join();//合并线程,使主线程与分支合并成为一个单线程} catch (Exception e) {// TODO: handle exception}for (int i = 0; i < 15; i++) {System.out.println("main is :" + i);}System.out.println("是不是很奇怪,居然先执行完了join线程然后才轮到main线程!");System.out.println("因为他们合在了一条线程");}}class Runner4 extends Thread{public void run() {for (int i = 0; i < 10; i++) {System.err.println("the join thread num is :" + i);try {sleep(1000);} catch (Exception e) {return;}}}}
the join thread num is :0
the join thread num is :1
the join thread num is :2
main is :0
main is :1
main is :2
是不是很奇怪,居然先执行完了join线程然后才轮到main线程!
因为他们合在了一条线程


5)isAlive()

package com.xiu.thread.test;/** *isAlive(),判断线程是否没有结束,没有则返回true * * @author xiu * @version 2017年8月7日 上午11:29:39  */public class ThreadTestIsAlive {public static void main(String[] args) {// TODO Auto-generated method stubIsAlive run = new IsAlive();run.run();System.out.println("the test thread is alive?  " + Thread.currentThread().isAlive()+"目前存活线程数为:"+ Thread.activeCount());}}class IsAlive extends Thread{public void run() {System.out.println("the test thread is alive?  " + Thread.currentThread().isAlive());for (int i = 0; i < 5; i++) {System.out.println("the test thread num is :" + i);}}}

the test thread is alive?  true
the test thread num is :0
the test thread num is :1
the test thread num is :2
the test thread num is :3
the test thread num is :4
the test thread is alive?  true目前存活线程数为:1

七)线程的调度——守护线程



八)线程的同步——同步方法、同步块

1)不用synchronized

package com.xiu.thread.test;/** *本来应该是第1个,第2个,但是因为同时进行,第一个在中间被打断。所以都成了第2个。 * * @author xiu * @version 2017年8月7日 上午11:42:33  */public class TestSynchronized1  implements Runnable{Syn syn = new Syn();public static void main(String[] args){TestSynchronized1 run = new TestSynchronized1();Thread thread1 = new Thread(run);Thread thread2 = new Thread(run);thread1.setName("thread-1");thread2.setName("thread-2");thread1.start();thread2.start();}@Overridepublic void run() {// TODO Auto-generated method stubsyn.add(Thread.currentThread().getName());}}class Syn {private static int num = 0;public void add(String name) {num ++;try {Thread.sleep(10);} catch (Exception e) {// TODO: handle exception}System.out.println(name + "你是第几个线程: " + num);for (int i = 0; i < 3; i++) {System.out.println("the num is : " + i + Thread.currentThread().getName());}}}
thread-1你是第几个线程: 2
the num is : 0thread-1
the num is : 1thread-1
thread-2你是第几个线程: 2
the num is : 0thread-2
the num is : 2thread-1
the num is : 1thread-2
the num is : 2thread-2

2)使用synchronized

package com.xiu.thread.test;/** *有顺序的执行 * * @author xiu * @version 2017年8月7日 上午11:42:33  */public class TestSynchronized2  implements Runnable{Syn1 syn = new Syn1();public static void main(String[] args){TestSynchronized2 run = new TestSynchronized2();Thread thread1 = new Thread(run);Thread thread2 = new Thread(run);thread1.setName("thread-1");//线程名字thread2.setName("thread-2");thread1.start();thread2.start();}@Overridepublic void run() {// TODO Auto-generated method stubsyn.add(Thread.currentThread().getName());//执行某个线程}}class Syn1 {private static int num = 0;public void add(String name) {synchronized (this) {//把当前对象锁起来,使这里得操作不会被打断,知道某个线程执行完毕才操作下一个线程num ++;try {Thread.sleep(10);} catch (Exception e) {// TODO: handle exception}System.out.println(name + "你是第几个线程: " + num);for (int i = 0; i < 3; i++) {System.out.println("the num is : " + i + Thread.currentThread().getName());}}}}

thread-1你是第几个线程: 1
the num is : 0thread-1
the num is : 1thread-1
the num is : 2thread-1
thread-2你是第几个线程: 2
the num is : 0thread-2
the num is : 1thread-2
the num is : 2thread-2


3)线程死锁

package com.xiu.thread.test;/** *都卡在那了,无法进行下一步,所以打不出“t2-->0”和“t2-->1”。 * * @author xiu * @version 2017年8月7日 下午1:56:22  */public class ThreadLock1 implements Runnable{static Thread t1 = null;static Thread t2 = null;public static void main(String[] args) {ThreadLock1 threadLock1 = new ThreadLock1();t1 = new Thread(threadLock1);t2 = new Thread(threadLock1);t1.setName("thread - 1");t2.setName("thread - 2");t1.start();t2.start();System.out.println("当前线程数量为:" +Thread.activeCount()+"当前线程为:"+Thread.currentThread().getName());}@Overridepublic void run() {// TODO Auto-generated method stubif (Thread.currentThread().getName().equals("thread - 1")) {synchronized (t1) {System.out.println("thread -1 ——>0");try {Thread.sleep(1000);} catch (Exception e) {// TODO: handle exception}synchronized (t2) {System.out.println("thread - 2 ——>0");}}}if (Thread.currentThread().getName().equals("thread - 2")) {synchronized (t2) {//锁住线程2System.out.println("thread -1 ——>1");try {Thread.sleep(1000);//线程2睡眠1秒} catch (Exception e) {// TODO: handle exception}synchronized (t1) {System.out.println("thread - 2 ——>1");}}}}}

thread -1 ——>0
thread -1 ——>1
当前线程数量为:3当前线程为:main

4)总结:

        当一个方法再对一个值进行修改时, 如果只是读取的话,则不用加synchronized,加了效率反而降低了。

        如果两个方法都对一个值进行修改的话,则这两个方法都要加上synchronized这样才不冲突,因为会先执行完一个后才会执行下一个。


九)线程并发协作——消费者与生产者模型

package com.xiu.thread.test;/** *生产者消费者线程模型简单实例 * * @author xiu * @version 2017年8月7日 下午2:08:33  */public class ThreadFactory {public static void main(String[] args) {// TODO Auto-generated method stubLanZi lZi = new LanZi();//创建一个篮子对象,该篮子可以放10个mantUsers users = new Users(lZi);//一个吃货ShengChan sc = new ShengChan(lZi);//一个生产者new Thread(users).start();//吃货开吃new Thread(sc).start();//生产者生产}}/** *生产一个有序号的馒头 * * @author xiu * @version 2017年8月7日 下午2:28:45  */class ManTuo{int id;public ManTuo(int id) {this.id = id;}public String toString() {return "馒头id ——>" + id;}}/** *篮子 * * @author xiu * @version 2017年8月7日 下午2:40:07  */class LanZi{int index = 0;ManTuo[] allManTuos = new ManTuo[6];//初始化可以放20个馒头的篮子public synchronized void eat(ManTuo mTuo) throws Exception {while(index == 0){//当篮子中馒头数量为0就停止吃this.wait();}this.notify();allManTuos[index] = mTuo;index --;//馒头减少1}public synchronized void add(ManTuo wt) throws Exception{while (index == 6) {//当生产的馒头数量达到篮子最大容量20个就停止生产this.wait();}this.notify();index ++;//馒头增加1allManTuos[index] = wt;}}/** *吃货 * * @author xiu * @version 2017年8月7日 下午2:36:29  */class Users implements Runnable{LanZi lz = null;public Users(LanZi lz) {//拉一个吃货进来,每个吃货有一只篮子this.lz = lz;}@Overridepublic void run() {// TODO Auto-generated method stubfor (int i = 0; i < 20; i++) {//一个吃货打算吃30个馒头ManTuo mTuo = new ManTuo(i);//吃货从篮子中拿出一个馒头开吃System.out.println("users ——>" + mTuo.toString());try {lz.eat(mTuo);} catch (Exception e) {// TODO: handle exception}}}}/** *生产者 * * @author xiu * @version 2017年8月7日 下午2:36:41  */class ShengChan implements Runnable{LanZi lZi = null;public ShengChan(LanZi lZi) {this.lZi = lZi;}@Overridepublic void run() {// TODO Auto-generated method stubfor(int i=0; i<20;i++){ManTuo wt=new ManTuo(i);System.out.println("ShenChang-->"+ wt.toString());//生产者生产一个馒头try {lZi.add(wt);//把馒头放进篮子中} catch (Exception e) {e.printStackTrace();}}}}

users ——>馒头id ——>0
ShenChang-->馒头id ——>0
users ——>馒头id ——>1
ShenChang-->馒头id ——>1
ShenChang-->馒头id ——>2
users ——>馒头id ——>2
users ——>馒头id ——>3
ShenChang-->馒头id ——>3
ShenChang-->馒头id ——>4
users ——>馒头id ——>4
users ——>馒头id ——>5
ShenChang-->馒头id ——>5
ShenChang-->馒头id ——>6
ShenChang-->馒头id ——>7
ShenChang-->馒头id ——>8
ShenChang-->馒头id ——>9
users ——>馒头id ——>6
users ——>馒头id ——>7
users ——>馒头id ——>8
users ——>馒头id ——>9




原创粉丝点击