Java多线程

1.使用阻塞队列(BlockingQueue)控制线程通信

package com.threadqueue.test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockQueue {
	public static void main(String[] args) throws InterruptedException {
		//定义一个长度为2的阻塞队列
		BlockingQueue<String> bq=new ArrayBlockingQueue<>(2);
		bq.put("Java");//与bq.add("Java"),bq.offer("Java")相同;
		bq.put("Java");//与bq.add("Java"),bq.offer("Java")相同;
		bq.put("Java");//阻塞线程
	}
}
package com.threadqueue.test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
//利用BlockQueue来实现进程间的通信
class Producer extends Thread
{
	private BlockingQueue<String> bq;
	public Producer(BlockingQueue<String> bq)
	{
		this.bq=bq;
	}
	public void run()
	{
		String[] strArr=new String[]
				{
					"Java","Python","Spring"
				};
		for(int i=0;i<6;i++)
		{
			System.out.println(getName()+"生产者准备生产集合元素!");
			try{
				Thread.sleep(200);
				//尝试放入元素,如果队列已满,则线程被阻塞
				bq.put(strArr[i%3]);
			}
			catch(Exception ex)
			{
				ex.printStackTrace();
			}
			System.out.println(getName()+"生产完成:"+bq);
		}
	}	
}
class Consumer extends Thread
{
	private BlockingQueue<String> bq;
	public Consumer(BlockingQueue<String> bq)
	{
		this.bq=bq;
	}
	public void run()
	{
		while(true)
		{
			System.out.println(getName()+"消费者准备消费集合元素!");
			try{
				Thread.sleep(200);
				//尝试取出元素,如果队列为空,则线程阻塞
				bq.take();
			}
			catch(Exception ex)
			{
				ex.printStackTrace();
			}
			System.out.println(getName()+"消费完成:"+bq);
		}
	}
	
}
public class BlockQueueTest {
	public static void main(String[] args) {
		//创建一个容量为1的BlockingQueue
		BlockingQueue<String> bq=new ArrayBlockingQueue<>(1);
		//启动3个生产线程
		new Producer(bq).start();
		new Producer(bq).start();
		new Producer(bq).start();
		//启动另一个消费者线程
		new Consumer(bq).start();
	}
}

3.线程和未处理的异常

package com.threadqueue.test;
class MyThread extends Thread{
	//提供指定线程名的构造器
	public MyThread(String name)
	{
		super(name);
	}
	//提供指定线程名、线程组的构造器
	public MyThread(ThreadGroup group,String name)
	{
		super(group,name);
	}
	public void run()
	{
		for(int i=0;i<5;i++)
		{
			System.out.println(getName()+"i的变量"+i);
		}
	}
}
public class ThreadGroupTest {
	public static void main(String[] args) {
		//获取主线程所在的线程组,这是所有线程默认的线程组
		ThreadGroup mainGroup=Thread.currentThread().getThreadGroup();
		System.out.println("主线程组的名字:"+mainGroup.getName());
		System.out.println("主线程组是否是后台线程:"+mainGroup.isDaemon());
		new MyThread("主线程组的线程").start();
		ThreadGroup tg=new ThreadGroup("新线程");
		tg.setDaemon(true);
		System.out.println("tg线程是否是后台线程:"+tg.isDaemon());
		MyThread tt=new MyThread(tg,"tg组的线程甲");
		tt.start();
		new MyThread(tg,"tg线程组的线程乙").start();
	}
}



package com.threadqueue.test;
//定义自己的异常处理器
class MyExHandler implements Thread.UncaughtExceptionHandler
{
	//实现UncaughtException()方法,该方法将处理线程的未处理异常
	public void uncaughtException(Thread t,Throwable e)
	{
		System.out.println(t+"线程出现了异常:"+e);
	}
}
public class ExThreadHandler {

	public static void main(String[] args) {
		//设置主线程的异常处理器
		Thread.currentThread().
		setUncaughtExceptionHandler(new MyExHandler());
		int a=2/0;
		System.out.println("程序正常结束!");
	}
}

4.线程池

package com.threadpool.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThrashPool {
	public static void main(String[] args) {
		//创建一个具有固定线程数(6)的线程池
		ExecutorService pool=Executors.newFixedThreadPool(6);
		//使用Lambda表达式创建Runnable对象
		Runnable target=()->{
			for(int i=0;i<5;i++)
			{
				System.out.println(Thread.currentThread().getName()+
						"的i值为:"+i);
			}
		};
		//向线程池中提交两个线程
		pool.submit(target);
		pool.submit(target);
		//关闭线程池
		pool.shutdown();
	}
}
package com.threadpool.test;
import java.util.List;
import java.util.concurrent.*;
//继承RecursiveAction来实现“可分解”的任务
class PrintTask extends RecursiveAction
{
	//每个小任务最多只打印20个数
	private static final int ts=10;
	private int start;
	private int end;
	//打印从start到end的任务
	public PrintTask(int start,int end)
	{
		this.start=start;
		this.end=end;
	}
	protected void compute()
	{
		//当end与start之间的差小于ThresHold时,开始打印
		if(end-start<ts)
		{
			for(int i=start;i<end;i++)
			{
				System.out.println(Thread.currentThread().getName()+
						"的i值:"+i);
			}
		}
		else
		{
			//当end与start之间的差大于ThresHold时,即要打印的数超过20
			//将大任务分解成两个“小任务”
			int middle=(start+end)/2;
			PrintTask left=new PrintTask(start,middle);
			PrintTask right=new PrintTask(middle,end);
			//并行执行两个小任务
			left.fork();
			right.fork();
		}
	}
}
public class ForkJoinPoolTest {
	public static void main(String[] args) throws InterruptedException {
		ForkJoinPool pool=new ForkJoinPool();
		//提交可分解的PrinTask任务
		pool.submit(new PrintTask(0,20));
		pool.awaitTermination(2,TimeUnit.SECONDS);
		//关闭线程池
		pool.shutdown();
	}

}

package com.threadpool.test;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
//继承RecursiveTask来实现可分解任务
class CalTask extends RecursiveTask<Integer>
{
	//每个小任务最多只累加10个数
	private static final int ts=10;
	private int arr[];
	private int start;
	private int end;
	//累加从start到end的数组元素
	public CalTask(int[] arr,int start,int end)
	{
		this.arr=arr;
		this.start=start;
		this.end=end;
	}
	protected Integer compute()
	{
		int sum=0;
		//当end与start之间的差小于ts时,开始进行累加
		if(end-start<ts)
		{
			for(int i=start;i<end;i++)
			{
				sum+=arr[i];
			}
			return sum;
		}
		else
		{
			//当end与start之间的差大于ts时,即要累加的数超过10个时
			//将大人物分解成两个小任务
			int middle=(start+end)/2;
			CalTask left=new CalTask(arr,start,middle);
			CalTask right=new CalTask(arr,middle,end);
			//并行执行两个小任务
			left.fork();
			right.fork();
			//把两个小任务累加的结果合并起来
			return (left.join()+right.join());
		}
	}
}
public class FJPSum {
	public static void main(String[] args) 
			throws InterruptedException, ExecutionException {
		int[] arr=new int[100];
		Random rand=new Random();
		int total=0;
		//初始化100个数字元素
		for(int i=0,len=arr.length;i<len;i++)
		{
			int tmp=rand.nextInt(30);
			//对数组元素赋值,并将数组元素添加到sum总和中
			total+=(arr[i]=tmp);
		}
		System.out.println(total);
		//创建一个通用池
		ForkJoinPool pool=ForkJoinPool.commonPool();
		//提交可分解的CalTask任务
		Future<Integer> future=pool.submit(
				new CalTask(arr,0,arr.length));
		System.out.println(future.get());
		//关闭线程池
		pool.shutdown();
	}
}

5.线程相关类

package com.threadlocal.test;
class Account{
	/*
	 * 定义一个ThreadLocal类型的变量,改变量是一个线程局部变量
	 * 每个线程都会保留该变量的构造器
	 */
	private ThreadLocal<String> name=new ThreadLocal<>();
	//定义一个初始化name成员变量的构造器
	public Account(String str)
	{
		this.name.set(str);
		//下面代码用于访问当前线程的name副本的值
		System.out.println("----"+this.name.get());
	}
	public String getName() {
		return name.get();
	}
	public void setName(String str) {
		this.name.set(str);
	}
}
class MyTest extends Thread
{
	//定义一个Account类型的成员变量
	private Account account;
	public MyTest(Account account,String name)
	{
		super(name);
		this.account=account;
	}
	public void run()
	{
		//循环十次
		for(int i=0;i<10;i++)
		{
			//当i==6时输出将账户名替换成当前线程名
			if(i==6)
			{
				account.setName(getName());
			}
			//输出同一个账户的账户名和循环变量
			System.out.println(account.getName()+
					"账户的i值:"+i);
		}
	}
	}
public class ThreadLocalTest {
	public static void main(String[] args) {
		//启动两个线程,两个线程共享同一个Account
		Account at=new Account("初始名");
		/*
		 * 虽然两个线程共享同一个账户,即只有一个账户名
		 * 但由于账户名是ThreadLocal类型的,所以每个线程都完全拥有各自的账户名副本,
		 * 因此在i==6之后,将看到两个线程访问同一个账户时出现不同的账户名
		 */
		new MyTest(at,"线程甲").start();
		new MyTest(at,"线程乙").start();
	}
}



























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值