java 7 并发 初级 学习记录(1)

1.认识线程:

    线程有2种启动方式,一种是实现Runnable接口,另一种是继承Thread类。

public class JavaCurrent {

	public static void main(String[] args) {
		Thread thread = new Thread(new InnerThread());
		thread.start();
	}
}


class InnerThread implements Runnable{

	@Override
	public void run() {
		//do something
	}
	
}

-----------------------------------------第二种-------------------------------------------

public class JavaCurrent {

	public static void main(String[] args) {
		InnerThread iThread = new InnerThread();
		iThread.start();
	}
}


class InnerThread extends Thread{

	@Override
	public void run() {
		//do something
	}
}

2. 线程有自己的属性:

    每个线程都有自己的属性,这些属性帮助我们更好地区分它们、观察它们的状态等。

    线程有id,name,Priority(优先级),status(状态)。

    id和name顾名思义,标示thread作用;优先级分为0-10,级数越高说明优先级越高;状态比较重要,有以下几个:

    new(初始化), runnable(运行), blocked(堵塞), waiting(等待),terminated(死亡). 具体详情以后解释。


3.去打断一个线程:

    线程Thread都有检验自身是否被打断的方法机制,通过isInterrupted()方法来检测当前运行线程是否被打断了。可以通过thread.interrupt()来打断线程,但是,神奇的是当一个线程在运行的时候,调用这个方法完全没有效果 ⊙﹏⊙b汗,线程依旧欢快地运行着。。。

public class JavaCurrent {

	public static void main(String[] args) {
		Thread thread = new Thread(new BeInterruptThread());
		thread.start();
		try {
			Thread.sleep(3000);
		} catch (Exception e) {
			e.printStackTrace();
		}
		thread.interrupt();
	}
	
	
}

class BeInterruptThread extends Thread{

	@Override
	public void run() {
		while(true){
			if(isInterrupted()){
				System.out.println("thread has been Interrupted");
				break;
			}else{
				System.out.println("always running");
			}
		}
	}
	
}

永远都不会打印出“thread has been Interrupted”,如何是好。。。

后来发现,问题出在isInterrupted()方法上,估计是直接调用父类中的isInterrupted()方法,只是获取父类的interrupt属性值,而不是BeInterruptThread对象中的interrupt属性,此处应该改为

        @Override
	public void run() {
		while(true){
			if(Thread.currentThread().isInterrupted()){
				System.out.println("thread has been Interrupted");
				break;
			}else{
				System.out.println("always running");
			}
		}
	}

有些时候我们需要在线程遇到打断,或者阻塞时进行线程的退出,这个时候需要使用抛出InterruptedException来实现。

4.使当前运行的线程暂定一下

    有时候,想让线程执行一定时期让他暂停,过一段时间之后再让它重新跑起来,在一些周期性的操作业务中经常出现

,我们可以使用sleep()方法。

public class JavaCurrent {

	public static void main(String[] args) {
		Thread thread = new Thread(new SleepThread());
		thread.start();
	}
	
	
}

class SleepThread implements Runnable{

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			try {
				TimeUnit.SECONDS.sleep(1);//暂定一秒哦
			} catch (InterruptedException e) {
				System.out.println("mission failed");
				break;
			}
			System.out.println("i am counting:" + i);
		}
	}

}

另外线程在sleep的时候,遇到interrupt的话,会直接抛出InterruptedException,并不会等待sleep结束。

5.让主线程等待

    这个想法其实就是让异步的线程变成同步线程,很神奇哈哈。当我们新开一个线程的时候,让执行线程(主线程)等待新开线程执行完毕之后,在继续下去。一般用在一些初始化的地方。

    可以使用Thread类中的join()方法

public class JavaCurrent {

	public static void main(String[] args) {
		Thread thread1 = new Thread(new JoinThread1(),"first");
		Thread thread2 = new Thread(new JoinThread2(),"second");
		thread1.start();
		thread2.start();
		try {
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("运行结束");
	}
	
	
}

class JoinThread1 implements Runnable{

	@Override
	public void run() {
		
		System.out.println("begin "+Thread.currentThread().getName()+" run()");
		try {
			TimeUnit.SECONDS.sleep(4);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("end "+Thread.currentThread().getName()+" run()");
	}

}

class JoinThread2 implements Runnable{

	@Override
	public void run() {
		System.out.println("begin "+Thread.currentThread().getName()+" run()");
		try {
			TimeUnit.SECONDS.sleep(6);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("end "+Thread.currentThread().getName()+" run()");
	}

}

6.让线程抛出异常

    我们知道在run()方法中没法去抛出捕捉的异常,可以换一种方式。使用UncaughtExceptionHandler。

public class JavaCurrent {

	public static void main(String[] args) {
	    Task task = new Task();
	    Thread thread = new Thread(task);
	    thread.setUncaughtExceptionHandler(new ThreadUnCaughtExceptionHandler());
	    thread.start();
	}
}


class Task implements Runnable{

	@Override
	public void run() {
		int isnum = Integer.parseInt("TTT");
	}
	
}

public class ThreadUnCaughtExceptionHandler implements UncaughtExceptionHandler{

	@Override
	public void uncaughtException(Thread t, Throwable e) {
	    
	    System.out.printf("Thread: %s\n",t.getId());
	    e.printStackTrace();
	}

}

7.本地线程变量

    当多个线程同时去执行一个任务对象的时候,他们都在同时使用任务对象中的属性,这是很多情况所不允许的。可以使用一个简单的方法 thread_local 。把需要进行本地线程化的变量声明为:

    static ThreadLocal<T> tl= new ThreadLocal<T>() 即可。这样每个线程都有自己的属性,相互之间不受干扰。

8.线程组管理

    统一管理一组线程的情况很有可能发生,比如几个线程都去找某个目标,其中一个找到目标的话,就回馈信息,并且退出所有其他线程。这里给出一个ThreadGroup的例子。

public class JavaCurrent {

	public static int num = 1345; 
	
	public static void main(String[] args) {
		
		NumGenerate ng = new NumGenerate(1000);
		int[][] array = ng.getDoubleArrray();
		//建立线程组
		ThreadGroup threadGroup = new ThreadGroup("Search");
		for (int i = 0; i < 5; i++) {//开5个线程
			SearchThread st = new SearchThread(threadGroup,i+"", array);
			st.start();
		}
		waitFinish(threadGroup);
	}
	
	private static void waitFinish(ThreadGroup threadGroup) {
		while(true){
			if(threadGroup.activeCount() < 5){//如果正在运行的线程数少于5个了,标示其中一个线程已经运行完毕
				threadGroup.interrupt();
		    	        break;
			}
			//检验线程的状态,如果5个线程全部都是休眠的话,也进行中断退出
			Thread[] threads = new Thread[threadGroup.activeCount()];
			threadGroup.enumerate(threads);
			int isSleepCount = 0;
			for (int i = 0; i < threads.length; i++) {
				if(threads[i].getState() == State.TIMED_WAITING){
					isSleepCount++;
				}
			}
			if(isSleepCount == 5){//说明5个线程都在休眠
				threadGroup.interrupt();
				System.out.println("all threads are not found !");
				break;
			}
		}
	}
}

public class SearchThread extends Thread{

	private String name;//标记一下线程的名字
	private int[][] targetArea;//目标数组
	
	public SearchThread(ThreadGroup tg ,String name,int[][] targetArea) {
		super(tg, name);
		this.name = name;
		this.targetArea = targetArea;
	}
	
	@Override
	public void run() {
		int i = Integer.parseInt(this.name);//确定该线程去跑哪行数组
		for (int j = 0; j < this.targetArea[i].length; j++) {
			if(this.targetArea[i][j] == JavaCurrent.num){//说明找到数字了
				System.out.println("thread"+this.name+": find the number!-->" + this.targetArea[i][j]+"==============================="); 
				return;
			}
		}
		try {
			TimeUnit.MINUTES.sleep(MIN_PRIORITY);//进入休眠1分钟
		} catch (InterruptedException e) {
			System.out.println("thread" +this.name+ ":quit!");
		}
	}
}

/**
 * 不重复的随机生成数
 * 如果传入的size是1000,那么就生成0-2000范围内的数字,两倍大小
 * @author dlsm-syq
 *
 */
public class NumGenerate {

	private int size;//需要生成随机数的数量
	
	private Random random = new Random();
	
	private Set<Integer> sets = new HashSet<Integer>();
	
	public NumGenerate(int size) {
		this.size = size;
		generate();
	}
	
	private void generate() {
		while(sets.size() != size){//只要sets容器还没有充满,就一直生成
			int i = random.nextInt(this.size * 2);
			if(!sets.contains(i)){
				sets.add(i);
			}
		}
	}
	
	//获取二维数组,只有5行,因为只开了5个线程
	public int[][] getDoubleArrray(){
		int col = this.size / 5;//每行有多少列
		int[][] array = new int[5][col];
		for (Iterator<Integer> iterator = sets.iterator(); iterator.hasNext();) {
			for (int i = 0; i < 5; i++) {
				for (int j = 0; j < col; j++) {
					array[i][j] = iterator.next();
				}
			}
		}
		return array;
	}
}

    开5个线程,去搜索一个二维数组中的某个数字,只要其中一个线程找到了,就中断所有线程。如果线程没有找到该数字,则进行长时间休眠,如果5个线程都没有找到该数字,则中断所有线程。

9.线程工厂类

    使用工厂模式来生产线程,方便线程的管理。主要用法是实现ThreadFactory接口,并且复写public Thread newThread(Runnable r)方法即可,非常简单。

public class MyThreadFactory implements ThreadFactory{
	
	private String name;
	private int count = 0;
	
	public MyThreadFactory(String name) {
		this.name = name;
	}
	
	
	@Override
	public Thread newThread(Runnable r) {
		Thread thread = new Thread(r,this.name + "prudct:" + count);
		this.count ++;
		return thread;
	}

}

public class JavaCurrent {

	public static void main(String[] args) {
		MyThreadFactory mtf = new MyThreadFactory("factory");
		for (int i = 0; i < 4; i++) {
			Thread t = mtf.newThread(new Task());
			t.start();
		}
	}
}


class Task implements Runnable{

	@Override
	public void run() {
		System.out.println(this.toString());
	}
	
}


    以上文章均是自己对书本中知识的理解,练手小例子,可能有许多错误的地方,还希望大家多多包含和指导,谢谢。

你可能感兴趣的:(并发,java7,初级)