Java多线程基础(二)

来源:互联网 发布:淘宝联盟用了红包丢单 编辑:程序博客网 时间:2024/05/20 16:35

Java多线程理解

一、常用方法

1、join()方法,让一个线程等待另一个线程执行完之后再执行。例如:A线程执行体中执行B线程的join方法,那么需要等到B线程执行完毕之后再执行A线程。

示例:

public class MyRunnable implements Runnable{private boolean flag = false;@Overridepublic void run() {for(int i = 0 ; i < 100 && !flag ; i++){System.out.println(Thread.currentThread().getName()+"---"+i);}}}
public class Test extends Thread{public static void main(String[] args) throws InterruptedException, ExecutionException {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);for(int i = 0 ; i < 100 ; i++){System.out.println(Thread.currentThread().getName()+"--"+i);if(i == 30){thread.start();thread.join();}}}}
当i== 30时,在主线程中插入thread线程,直到thread线程执行完毕,主线程才开始执行。
2、sleep():让线程暂停执行指定的时间。由于线程不是出于就绪状态,在指定时间之内,线程不能执行。特殊应用:当new一个线程并调用start()方法之后,线程需要等待某个时间获取CPU时间片才能执行,如果希望这个线程立即执行,可以使用sleep(1),当然这个立即执行的线程不一定是多线程中的哪一个。

public class Test extends Thread{public static void main(String[] args) throws InterruptedException, ExecutionException {MyRunnable myRunnable = new MyRunnable();Thread thread1 = new Thread(myRunnable);thread1.setName("A");Thread thread2 = new Thread(myRunnable);thread2.setName("B");Thread thread3 = new Thread(myRunnable);thread3.setName("C");for(int i = 0 ; i < 100 ; i++){System.out.println(Thread.currentThread().getName()+"---"+i);if(i==30){thread1.start();Thread.sleep(1);}if(i==40){thread2.start();Thread.sleep(1);}if(i==50){thread3.start();Thread.sleep(1);}}}}
class MyRunnable implements Runnable {    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(Thread.currentThread().getName() + " " + i);        }    }}

3、后台线程

     概念/目的:后台线程主要是为其他线程(相对可以称之为前台线程)提供服务,或守护线程。如JVM中的垃圾回收线程。

     生命周期:后台线程的生命周期与前台线程生命周期有一定关联。主要体现在:当所有的前台线程都进入死亡状态时,后台线程会自动死亡(其实这个也很好理解,因为后台线程存在的目的在于为前台线程服务的,既然所有的前台线程都死亡了,那它自己还留着有什么用...伟大啊 ! !)

设置后台线程:调用Thread对象的setDaemon(true)方法可以将指定的线程设置为后台线程。

       判断线程是否是后台线程:调用thread对象的isDeamon()方法。

注:main线程默认是前台线程,前台线程创建中创建的子线程默认是前台线程,后台线程中创建的线程默认是后台线程。调用setDeamon(true)方法将前台线程设置为后台线程时,需要在start()方法调用之前。前天线程都死亡后,JVM通知后台线程死亡,但从接收指令到作出响应,需要一定的时间。
public class Test extends Thread{public static void main(String[] args) throws InterruptedException, ExecutionException {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);for(int i = 0 ; i < 10 ; i++){System.out.println(Thread.currentThread().getName()+"--"+i);if(i == 3){thread.setDaemon(true);thread.start();}}}}
public class MyRunnable implements Runnable{private boolean flag = false;@Overridepublic void run() {for(int i = 0 ; i < 10000 && !flag ; i++){System.out.println(Thread.currentThread().getName()+"---"+i);}}public void stoped(){this.flag = true;}}
执行结果:

main--0main--1main--2main--3main--4main--5main--6main--7main--8main--9Thread-0---0Thread-0---1Thread-0---2Thread-0---3Thread-0---4Thread-0---5Thread-0---6Thread-0---7Thread-0---8Thread-0---9
4、常用的快速终止线程的方法

       一般线程状态分成就绪状态、运行状态、死亡状态。

就绪状态转换成运行状态:线程得到处理器资源

运行状态转换成就绪窗台:此线程主动执行yeild()方法或者再运行过程中失去处理器资源。

运行状态转成死亡状态: 线程执行体执行结束或者发生了异常。

       此处需要特别注意的是:当调用线程的yield()方法时,线程从运行状态转换为就绪状态,但接下来CPU调度就绪状态中的哪个线程具有一定的随机性,因此,可能会出现A线程调用了yield()方法后,接下来CPU仍然调度了A线程的情况。

       由于实际的业务需要,常常会遇到需要在特定时机终止某一线程的运行,使其进入到死亡状态。目前最通用的做法是设置一boolean型的变量,当条件满足时,使线程执行体快速执行完毕。如:

 
public class MyRunnable implements Runnable{private boolean flag = false;@Overridepublic void run() {for(int i = 0 ; i < 10000 && !flag ; i++){System.out.println(Thread.currentThread().getName()+"---"+i);}}public void stoped(){this.flag = true;}}
public class Test extends Thread{public static void main(String[] args) throws InterruptedException, ExecutionException {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);for(int i = 0 ; i < 10000000 ; i++){if(i==3){thread.start();}if(i == 400000){myRunnable.stoped();}}}}
二、对象及变量的并发访问

1、(1)方法内变量是线程安全的

public class SelfNum  {public void addI(String name){int num = 0;if("a".equals(name)){num = 100;System.out.println(ThreadA.currentThread().getName()+",a set over");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if("b".equals(name)){num = 200;System.out.println(ThreadA.currentThread().getName()+",b set over");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(ThreadA.currentThread().getName()+",当前num值是:"+num);}}
(2)实例变量非线程安全
public class SelfNum  {private int num = 0;public void addI(String name){if("a".equals(name)){num = 100;System.out.println(ThreadA.currentThread().getName()+",a set over");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if("b".equals(name)){num = 200;System.out.println(ThreadA.currentThread().getName()+",b set over");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println(ThreadA.currentThread().getName()+",当前num值是:"+num);}}
测试:

public class MainTest {public static void main(String[] args) {SelfNum selfNum = new SelfNum();ThreadA threadA = new ThreadA(selfNum);ThreadB threadB = new ThreadB(selfNum);threadA.start();threadB.start();}}
第一种情况结果:

Thread-0,a set overThread-1,b set overThread-1,当前num值是:200Thread-0,当前num值是:100

第二种情况结果:

Thread-0,a set overThread-1,b set overThread-0,当前num值是:200Thread-1,当前num值是:200

0 0
原创粉丝点击