Java多线程与并发

线程和进程的由来

串行:初期的计算机智能串行任务,需要长时间等待用户输入

批处理:预先将用户的指令集中成清单,批量串行处理用户指令,仍然无法并发执行

进程:进程读占内存空间,保存各自运行状态,互相间不干扰且互相切换,为并发处理任务提供了可能

线程:共享进程的内存资源,相互间切换更快捷,支持更细粒度的任务控制,使进程的子任务得以并发执行

 

进程是资源分配的最小单位,线程是CPU调度的最小单位

所有与进程相关的资源,都被记录在PCB中

进程是抢占处理机的调度单位;线程属于某个进程,共享其资源

线程只有堆栈寄存器、程序计数器和TCB组成

 

总结

线程不能看做独立应用,而进程可看做独立应用

进程有独立的地址空间,相互不影响,线程只是进程的不同执行路径

线程没有独立的地址空间,多进程的程序比多线程程序健壮

进程的切换比线程的切换开销大

 

Java进程和线程的关系

Java对操作系统提供的功能进行封装,包括进程和线程

运行一个程序会产生一个进程,进程包含至少一个线程

每个进程对应一个JVM实例,多个线程共享JVM里的堆

Java采用单线程编程模型,程序会自动创建主线程

主线程可以创建子线程,原则上要后于子线程完成执行

Thread中start和run方法的区别

package com.binglian.thread;

public class CurrentThreadDemo {

	public static void main(String[] args) {
		System.out.println("Current Thread:"+Thread.currentThread().getName());
	}
}

 

 

Thread的run启动

它一样还是 main线程

package com.binglian.thread;

public class ThreadTest {
	
	private static void attack(){
		
		System.out.println("Fight");
		System.out.println("Current Thread is:"+Thread.currentThread().getName());
	}
	
	public static void main(String[] args) {
		Thread thread=new Thread(){
			public void run() {
				attack();
			}
		};
		
		System.out.println("current main thread is:"+Thread.currentThread().getName());
		thread.run();
	}

}

 

 

Thread的start方法

它会创建新的子线程去启动

package com.binglian.thread;

public class ThreadTest {
	
	private static void attack(){
		
		System.out.println("Fight");
		System.out.println("Current Thread is:"+Thread.currentThread().getName());
	}
	
	public static void main(String[] args) {
		Thread thread=new Thread(){
			public void run() {
				attack();
			}
		};
		
		System.out.println("current main thread is:"+Thread.currentThread().getName());
		thread.start();
	}

}

 

 

总结

调用start()方法会创建一个新的子线程并启动

run()方法只是Thread的一个普通方法的调用

 


 

 

Thread和Runnable的关系

 

Thread是实现了Runnable接口的类,使得run支持多线程

因类的单一继承,推荐多使用Runnable接口

 

 

 

Thread 实现多线程

MyThread方法 继承Thread

package com.binglian.thread;

public class MyThread extends Thread{
	
	private String name;
	
	public MyThread(String name){
		this.name=name;
	}

	@Override
	public void run(){
		for(int i=0;i<10;i++){
			System.out.println("Thread start :"+this.name+",i="+i);
		}
	}
}

 

package com.binglian.thread;

public class ThreadDemo {

	public static void main(String[] args) {
		MyThread myThread1=new MyThread("Thread1");
		MyThread myThread2=new MyThread("Thread2");
		MyThread myThread3=new MyThread("Thread3");
		
		myThread1.start();
		myThread2.start();
		myThread3.start();
	}
}

 

它交互执行的

也就是说 线程1还没执行完 线程2就已经开始执行了

实现了多线程

 

 

Runnable实现接口

package com.binglian.thread;

public class MyRunnable implements Runnable{

	private String name;
	
	public MyRunnable(String name){
		this.name=name;
	}
	
	
	public void run() {
		for(int i=0;i<10;i++){
			System.out.println("Thread start :"+this.name+",i="+i);
		}
	}
	
	
}

 

 

package com.binglian.thread;

public class RunnableDemo {

	public static void main(String[] args) {
		MyRunnable myRunnable1=new MyRunnable("Runnable1");
		MyRunnable myRunnable2=new MyRunnable("Runnable2");
		MyRunnable myRunnable3=new MyRunnable("Runnable3");
	
		Thread thread1=new Thread(myRunnable1);
		Thread thread2=new Thread(myRunnable2);
		Thread thread3=new Thread(myRunnable3);
	
		thread1.start();
		thread2.start();
		thread3.start();
	}
}

 

 


 

 

如何给run()方法传参

实现的方式主要有三种

构造函数传参

成员变量传参

回调函数传参

 

 

如何实现处理线程的返回值

实现的方法主要有三种

主线程等待法

使用Thread类的join()阻塞当前线程以等待子线程处理完毕

package com.binglian.thread;

public class CycleWait implements Runnable{

	private String value;
	
	public void run() {
		
		try {
			Thread.currentThread().sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		value="we have data now";
	}

	
	public static void main(String[] args) throws InterruptedException {
		
		CycleWait cycleWait=new CycleWait();
		
		Thread thread=new Thread(cycleWait);

		thread.start();

//		while(cycleWait.value==null){
//			Thread.currentThread().sleep(100); 启动后休眠 可以获得value的值
//		}
		thread.join();
		System.out.println("value :"+cycleWait.value);
	}
	
	
}

通过Callable接口实现:通过FutureTask Or线程池获取

 

public class MyCallable implements Callable<String> {

	public String call() throws Exception {
		
		String value="test";
		System.out.println("Read to work");
		Thread.currentThread().sleep(5000);
		System.out.println("task done");
		return value;
	}

}
public class FutureTaskDemo {
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<String> task=new FutureTask<String>(new MyCallable());
		new Thread(task).start();
		if(!task.isDone()){
			System.out.println("task has not finished,please wait!");
		}
		System.out.println("task return:"+task.get());
	}
}

 

package com.binglian.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ThreadPoolDemo {

	//第二种 线程池实现
	public static void main(String[] args) {
		//定义一个线程池
		ExecutorService executorService=Executors.newCachedThreadPool();
		//往线程池添加任务
		Future<String> future = executorService.submit(new MyCallable());
		
		if(!future.isDone()){
			System.out.println("task has not finished, please wait!");
		}
		
		try{
			System.out.println(future.get());
		}catch (InterruptedException e) {
			e.printStackTrace();
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			executorService.shutdown();
		}
	}

}

线程的状态

六个状态

新建(New):创建后尚未启动的线程的状态

运行(Runnable):包含Running和Ready

无限期等待(Waiting):不会被分配CPU执行时间,需要显式被换醒

限期等待(Timed Waiting):在一定时间后会由系统自动唤醒

阻塞(Blocked):等待获取排它锁

结束(Terminated):已终止线程的状态,线程已经结束执行

package com.binglian.thread;

public class ThreadTest {
	
	private static void attack(){
		
		System.out.println("Fight");
		System.out.println("Current Thread is:"+Thread.currentThread().getName());
	}
	
	public static void main(String[] args) throws InterruptedException {
		Thread thread=new Thread(){
			public void run() {
				attack();
			}
		};
		
		System.out.println("current main thread is:"+Thread.currentThread().getName());
		thread.start();
		thread.join();
		thread.run();
	}

}

以下会出现无限期等待

没有设置Timeout参数的Oject.wait()方法

没有设置Timeout参数的Thread.join()方法

LockSupport.park()方法

 

以下会出现限期等待

Thread.sleep()方法。

设置了Timeout参数的Object.wait()方法

设置了Timeout参数的Thread.join()方法

LockSupport.parkNanos()方法

LockSupport.parkUntil()方法

 

sleep和wait的区别

基本的差别

sleep是Thread类的方法,wait是Object类中定义的方法

sleep()方法可以在任何地方使用

wait()方法只能在synchronized方法或synchronized块中使用

 

最主要的本质区别

Thread.sleep只会让出CPU,不会导致锁行为的改变

Object.wait不仅让出CPU,还会释放已经占有的同步资源锁

 

两种情况

package com.binglian.thread;

public class WaitSleepDemo {

	public static void main(String[] args) {
		final Object lock=new Object();
		new Thread(new Runnable() {
			
			public void run() {
				System.out.println("thread A is waiting to get lock");
				synchronized(lock){
					try{
						System.out.println("thread A get lock");
						Thread.sleep(20);
						System.out.println("thread A do wait method");
						lock.wait(1000);
						System.out.println("thread A is done");
					}catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
		
		
		try {
			Thread.sleep(10);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		new Thread(new Runnable() {
			
			public void run() {
				System.out.println("thread B is waiting to get lock");
				synchronized(lock){
					try{
						System.out.println("thread B get lock");
						System.out.println("thread B is sleeping 10  ms");
						Thread.sleep(20);
						
						System.out.println("thread B is done");
					}catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
}

 

 

notify和notifyAll的区别

要先了解两个概念

锁池EntryList

等待池WaitSet

 

锁池

假设线程A已经拥有了某个对象(不是类)的锁,而其他线程B、C想要调用这个对象的某个synchronized方法(或者块),由于B、C线程在进入对象的synchronized方法(或者块)之前必须先获得该对象锁的拥有权,而恰巧该对象的锁目前被线程A所占用,此时B、C线程就会被堵塞,进入一个地方去等待锁的释放,这个地方便是该对象的锁池

 

等待池

假设线程A调用了某个对象的wait()方法,线程A就会被释放该对象的锁,同时线程A就进入到了该对象的等待池中,进入到等待池中的线程就不会去竞争去该对象的锁

 

notify和notifyAll的区别

notifyAll会让所有处于等待池的线程全部进入锁池去竞争获取锁的机会

notify只会随机选取一个处于等待池中的线程进入锁池去竞争获取锁的机会。

package com.binglian.thread;

public class WaitSleepDemo {

	public static void main(String[] args) {
		final Object lock=new Object();
		new Thread(new Runnable() {
			
			public void run() {
				System.out.println("thread A is waiting to get lock");
				synchronized(lock){//进入synchronized中或块中
					try{
						System.out.println("thread A get lock");
						Thread.sleep(20);
						System.out.println("thread A do wait method");
						lock.wait();//进入等待池中。除非被 notifyAll唤醒
						System.out.println("thread A is done");
					}catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
		
		
		try {
			Thread.sleep(10);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		new Thread(new Runnable() {
			
			
			public void run() {
				System.out.println("thread B is waiting to get lock");
				synchronized(lock){//进入synchronized中或块中
					try{
						System.out.println("thread B get lock");
						System.out.println("thread B is sleeping 10  ms");
						Thread.sleep(20);
						
						System.out.println("thread B is done");
						
						lock.notify();
					}catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
}

 

 

private volatile boolean go=false;这个是对内存的读写操作(原子性,可见的)

 

可见性(最重要的特性)。对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

原子性。对任意(包括64位long类型和double类型)单个volatile变量的读/写具有原子性。但是类型于a++这种复合操作不具有原子性。

package com.binglian.thread;

public class NotificationDemo {
	package com.binglian.thread;

public class NotificationDemo {
	private volatile boolean go=false;
	
	public static void main(String[] args) throws InterruptedException {
		
		final NotificationDemo test=new NotificationDemo();
		
		Runnable waitTask=new Runnable() {
			
			public void run() {
				try {
					test.shouldGo();
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"finished Exception");
			}
		};
	
		Runnable notifyTask =new Runnable() {
			
			public void run() {
				test.go();
				System.out.println(Thread.currentThread().getName()+"finished Exception");
			}
		};
		
		Thread thread1=new Thread(waitTask,"WT1");
		Thread thread2=new Thread(waitTask,"WT2");
		Thread thread3=new Thread(waitTask,"WT3");
		Thread thread4=new Thread(notifyTask,"NT1");
		
		//starting all waiting thread
		thread1.start();
		thread2.start();
		thread3.start();
		
		Thread.sleep(2000);
		
		thread4.start();
	}
	
	
	private synchronized void shouldGo() throws InterruptedException{
		while(go !=true){
			System.out.println(Thread.currentThread()+"is going to wait on this object");
			wait();
			System.out.println(Thread.currentThread()+"is woken up");
		}
		go=false;
	}
	
	private synchronized void go(){
		while(go == false){
			System.out.println(Thread.currentThread()
					+"is going to notify all or one thread waiting on this object");
			go=true;
			notify();
		}
	}
}

	
	public static void main(String[] args) throws InterruptedException {
		
		final NotificationDemo test=new NotificationDemo();
		
		Runnable waitTask=new Runnable() {
			
			public void run() {
				try {
					test.shouldGo();
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"finished Exception");
			}
		};
	
		Runnable notifyTask =new Runnable() {
			
			public void run() {
				test.go();
				System.out.println(Thread.currentThread().getName()+"finished Exception");
			}
		};
		
		Thread thread1=new Thread(waitTask,"WT1");
		Thread thread2=new Thread(waitTask,"WT2");
		Thread thread3=new Thread(waitTask,"WT3");
		Thread thread4=new Thread(notifyTask,"NT1");
		
		//starting all waiting thread
		thread1.start();
		thread2.start();
		thread3.start();
		
		Thread.sleep(2000);
		
		thread4.start();
	}
	
	
	private synchronized void shouldGo() throws InterruptedException{
		while(go !=true){
			System.out.println(Thread.currentThread()+"is going to wait on this object");
			wait();
			System.out.println(Thread.currentThread()+"is woken up");
		}
		go=false;
	}
	
	private synchronized void go(){
		while(go == false){
			System.out.println(Thread.currentThread()
					+"is going to notify all or one thread waiting on this object");
			go=true;
			notify();
		}
	}
}

yield

概念

当调用Thread.yield()函数时,会给线程调度器一个当前线程愿意让出CPU使用的暗示,但是线程调度器可能会忽略这个暗示。

 

我的理解就是 把他比作皇上,他要让位了,让太子上位,而太子选择无视,不当,皇帝只能继续当或者其他皇兄当

package com.binglian.thread;

public class YieldDemo {
	
	public static void main(String[] args) {
		
		Runnable yieldTask=new Runnable() {
			
			public void run() {
				for(int i=1;i<=10;i++){
					System.out.println(Thread.currentThread().getName()+i);
					if(i==5){
						Thread.yield();
					}
				}
			}
		};
		
		Thread thread1=new Thread(yieldTask,"G");
		Thread thread2=new Thread(yieldTask,"T");
		thread1.start();
		thread2.start();
	}
}

 

如何中断线程

已经被抛弃的方法

通过调用stop()方法停止线程

通过调用suspend()和resume()方法

 

 

目前使用的方法

一、调用interrupt(),通过线程应该中断了

1.如果线程处于被堵塞状态,那么线程将立即退出被堵塞状态,并抛出一个InterruptedException异常

2.如果线程处于正常活动状态,那么会将该线程的中端标志设置为true。被设置中断标志的线程将继续正常运行,不受影响。

二、需要被调用的线程配合中断

 1.在正常运行任务时,经常检查本线程的中端断标志位,如果被设置了中断标志就自行停止线程。

2.如果线程处于正常活动状态,那么会该线程的中断标志设置为true。被设置中断标注线程将继续正常运行,不受影响。

package com.binglian.thread;

public class InterruptDemo {

	public static void main(String[] args) throws InterruptedException {
		
		Runnable interruptTask=new Runnable() {
			
			public void run() {
				int i=0;
				try{
					//在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志自行停止线程
					while(!Thread.currentThread().isInterrupted()){
						Thread.sleep(100);//休眠100ms
						i++;
						System.out.println(Thread.currentThread().getName()+"("+Thread.currentThread().getState()+") loop"+i);
					}
				}catch (InterruptedException e) {
					//在调用堵塞方法时正确处理InterrupedException异常。(例如。catch异常后就结束线程)
					System.out.println(Thread.currentThread().getName()+"("+Thread.currentThread().getState()+") catch InterruptedException");
				}
			}
		};
		
		Thread thread1=new Thread(interruptTask,"t1");
		System.out.println(thread1.getName()+"("+thread1.getState()+") is new.");
		
		thread1.start();
		System.out.println(thread1.getName()+"("+thread1.getState()+") is started.");
		
		
		//主线程休眠300ms,然后主线程给t1发"中断"指令。
		Thread.sleep(300);
		thread1.interrupt();
		System.out.println(thread1.getName()+"("+thread1.getState()+") is interrupted.");

		//主线程休眠300ms,然后查看t1的状态
		Thread.sleep(300);
		System.out.println(thread1.getName()+"("+thread1.getState()+") is interrupted now.");

	}
}

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值