Java多线程基础(二)

Java多线程理解

一、常用方法

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

示例:

public class MyRunnable implements Runnable{
	private boolean flag = false;
	@Override
	public 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;
	@Override
	public void run() {
		for(int i = 0 ; i < 10000 && !flag ; i++){
			System.out.println(Thread.currentThread().getName()+"---"+i);
		}
	}
	public void stoped(){
		this.flag = true;
	}
}
执行结果:

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

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

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

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

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

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

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

 
public class MyRunnable implements Runnable{
	private boolean flag = false;
	@Override
	public 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 block
				e.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 block
				e.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 block
				e.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 block
				e.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 over
Thread-1,b set over
Thread-1,当前num值是:200
Thread-0,当前num值是:100

第二种情况结果:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值