第一章线程管理
1.1、同步、异步
同步:多个线程一个一个执行
异步:多个线程一起抢着执行
1.2、线程的创建和运行
创建线程的方式:
1、继承Thread类,并且覆盖run()方法
2、实现Runnable接口的类。使用带参数的Thread构造器来创建Thread对象。这个参数就是Runnable接口的一个实现对象
示例:
public class ThreadCalculator extends Thread{
@Override public void run() { System.out.println("开启一个线程,并在线程中做一些事情"); System.out.println("ThreadName="+Thread.currentThread().getName()); }
public class ThreadMain { public static void main(String[] args) { for(int i=0;i<10;i++){ ThreadCalculator tc = new ThreadCalculator(); tc.start(); } } } |
public class Calculator implements Runnable {
private int number;
public Calculator(int number) { this.number=number; }
@Override public void run() { for (int i=1; i<=10; i++){ System.out.println("ThreadName="+Thread.currentThread().getName()+" "+number+" * "+i+" = "+(i*number)); } }
}
public class Main {
public static void main(String[] args) {
for (int i=1; i<=10; i++){ Calculator calculator=new Calculator(i); Thread thread=new Thread(calculator); thread.start(); } } }
|
1.3、线程信息的获取和设置
ID:线程的唯一标识符
Name:线程名称
Priority:线程的优先级,1~10之间,数值越高优先级越高。
Status:线程的状态。线程有6种状态:new、runnable、blocked、waiting、time waiting、terminated
public class Calculator implements Runnable {
private int number;
public Calculator(int number) { this.number=number; }
@Override public void run() { System.out.printf("%s: %d\n",Thread.currentThread().getName(),number,number); }
}
public class Main {
public static void main(String[] args) {
Thread threads[] = new Thread[10];
for (int i=0; i<10; i++){ threads[i]=new Thread(new Calculator(i)); if ((i%2)==0){ threads[i].setPriority(Thread.MAX_PRIORITY); } else { threads[i].setPriority(Thread.MIN_PRIORITY);
} threads[i].setName("Thread "+i); }
for (Thread thread : threads) { System.out.println("Thread-ID:" + thread.getId() + " Thread-Name:"+thread.getName() + " Thread Status:"+thread.getState()); } System.out.println("--------------------------------------------------------------------------"); for (Thread thread : threads) { thread.start(); System.out.println("Thread-ID:" + thread.getId() + " Thread-Name:"+thread.getName() + " Thread Status:"+thread.getState()); }
}
} |
1.4、线程的中断
public class PrimeGenerator extends Thread{
@Override public void run() {
while (true) { System.out.println("Threadn-Name"+Thread.currentThread().getName()); // When is interrupted, write a message and ends if (isInterrupted()) { System.out.println("The Prime Generator has been Interrupted\n"); return; } } }
}
public class Main {
public static void main(String[] args) {
Thread task=new PrimeGenerator(); task.start();
try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
task.interrupt(); }
} |
1.5、线程中断的控制
程序分析:以下程序主要是通过throw new InterruptedException();控制被run调用的方法,来终止被调用方法的继续执行,并非是终止线程!!!
|
public class FileSearch implements Runnable {
private String initPath;
private String fileName;
public FileSearch(String initPath, String fileName) { this.initPath = initPath; this.fileName = fileName; }
@Override public void run() { File file = new File(initPath); if (file.isDirectory()) { try { directoryProcess(file); } catch (InterruptedException e) { System.out.printf("%s: The search has been interrupted",Thread.currentThread().getName()); cleanResources(); } } }
private void cleanResources() {
}
private void directoryProcess(File file) throws InterruptedException {
File list[] = file.listFiles(); if (list != null) { for (int i = 0; i < list.length; i++) { if (list[i].isDirectory()) { directoryProcess(list[i]); } else { fileProcess(list[i]); } } } if (Thread.interrupted()) { throw new InterruptedException(); } }
private void fileProcess(File file) throws InterruptedException { if (file.getName().equals(fileName)) { System.out.printf("%s : %s\n",Thread.currentThread().getName() ,file.getAbsolutePath()); }
if (Thread.interrupted()) { throw new InterruptedException(); } }
}
public class Main {
public static void main(String[] args) { FileSearch searcher=new FileSearch("C:\\","autoexec.bat"); Thread thread=new Thread(searcher);
thread.start();
try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); }
thread.interrupt(); }
} |
1.6、线程的休眠和恢复
以下程序通过interrupt()方法来打断sleep休眠 Sleep是让程序挂起休眠 |
public class FileClock implements Runnable {
@Override public void run() { for (int i = 0; i < 10; i++) { System.out.printf("%s\n", new Date()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { System.out.println("The FileClock has been interrupted"); } } } }
public class Main {
public static void main(String[] args) { FileClock clock=new FileClock(); Thread thread=new Thread(clock);
thread.start(); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); };
thread.interrupt(); } } |
1.7、等待线程的终止
thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。 也就是说,下面的线程会等待上面的线程执行结束再去执行 |
class RunnableJob implements Runnable {
@Override public void run() { Thread thread = Thread.currentThread(); try { Thread.sleep(1000); System.out.println(thread.getName() + " end" + " at " + new Date()); } catch (InterruptedException e) { e.printStackTrace(); } }
}
public class BasicTest { public static void main(String[] args) throws InterruptedException { //初始化 RunnableJob runnableJob = new RunnableJob(); Thread T1 = new Thread(runnableJob, "T1"); Thread T2 = new Thread(runnableJob, "T2"); Thread T3 = new Thread(runnableJob, "T3");
//T2在T1执行完后执行,T3在T2执行完后执行 T1.start(); T1.join();
T2.start(); T2.join();
T3.start(); }
} |
1.8、守护线程的创建和运行
守护线程适合做监控等后台操作 |
public class Event {
private Date date;
private String event;
public Date getDate() { return date; }
public void setDate(Date date) { this.date = date; }
public String getEvent() { return event; }
public void setEvent(String event) { this.event = event; } }
public class WriterTask implements Runnable {
Deque<Event> deque;
public WriterTask (Deque<Event> deque){ this.deque=deque; }
@Override public void run() {
for (int i=1; i<100; i++) { Event event=new Event(); event.setDate(new Date()); event.setEvent("线程="+Thread.currentThread().getId()+"被创建");
deque.addFirst(event); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class CleanerTask extends Thread {
private Deque<Event> deque;
public CleanerTask(Deque<Event> deque) { this.deque = deque; setDaemon(true); }
@Override public void run() { while (true) { Date date = new Date(); clean(date); } }
private void clean(Date date) { long difference; boolean delete;
if (deque.size()==0) { return; }
delete=false; do { Event e = deque.getLast(); difference = date.getTime() - e.getDate().getTime(); if (difference > 10000) { System.out.println("清除事件: "+e.getEvent()); deque.removeLast(); delete=true; } } while (difference > 10000); if (delete){ System.out.println("清除后队列大小:"+deque.size()); } } }
public class Main {
public static void main(String[] args) {
Deque<Event> deque=new ArrayDeque<Event>();
WriterTask writer=new WriterTask(deque); for (int i=0; i<3; i++){ Thread thread=new Thread(writer); thread.start(); }
CleanerTask cleaner=new CleanerTask(deque); cleaner.start();
}
} |
1.9、线程中不可控异常的处理
在java中有两种异常 1、 非运行时异常:必须throws抛出或者捕获,比如IOException、ClassNotFoundException 2、 运行时异常:不必显示处理,是程序执行的过程中出现的异常。
因为run()方法不支持throws抛出异常,所以如果是非运行时必须处理时候,只能通过捕获来处理 如果出现运行时异常,会导致线程退出程序,需要手动去捕获处理异常,这里有两种方式,一种是手动try。。。catch,还有一种就是下面要讲解的在线程上设置捕获异常。 |
public class Task implements Runnable {
@Override public void run() { int numero=Integer.parseInt("TTT"); }
}
public class ExceptionHandler implements UncaughtExceptionHandler {
@Override public void uncaughtException(Thread t, Throwable e) { System.out.printf("An exception has been captured\n"); System.out.printf("Thread: %s\n",t.getId()); System.out.printf("Exception: %s: %s\n",e.getClass().getName(),e.getMessage()); System.out.printf("Stack Trace: \n"); e.printStackTrace(System.out); System.out.printf("Thread status: %s\n",t.getState()); }
}
public class Main {
public static void main(String[] args) { Task task=new Task(); Thread thread=new Thread(task); thread.setUncaughtExceptionHandler(new ExceptionHandler()); thread.start();
try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.printf("Thread has finished\n");
}
} |
1.10、线程局部变量的使用
通过继承Thread或者实现Runnable借口中,使用普通属性,会出现数据共享并发问题 可以通过ThreadLocal Variable线程局部变量来实现每个线程使用自己的单独属性 |
异常程序:count被累加了,说明是共享的 |
public class UnsafeTask implements Runnable{
public int count=1;
@Override public void run() { count++;
}
}
public class Main {
public static void main(String[] args) { UnsafeTask task=new UnsafeTask();
for (int i=0; i<10; i++){ Thread thread=new Thread(task); thread.start();
}
System.out.println(task.count); } } |
正确程序:count没有被累加,说明不是共享的 |
public class SafeTask implements Runnable {
public static ThreadLocal<Integer> count= new ThreadLocal<Integer>() { protected Integer initialValue(){ return 1; } };
@Override public void run() { count.set(count.get()+1); }
}
public class SafeMain {
public static void main(String[] args) { SafeTask task=new SafeTask();
for (int i=0; i<10000; i++){ Thread thread=new Thread(task); thread.start(); }
System.out.println(task.count.get());
}
} |
1.11、线程的分组
ThreadGroup tg = new ThreadGroup("ThreadGroup测试"); ThreadTask task1 = new ThreadTask(); ThreadTask task2 = new ThreadTask(); ThreadTask task3 = new ThreadTask();
Thread t1 = new Thread(tg,task1); Thread t2 = new Thread(tg,task2); Thread t3 = new Thread(tg,task3);
t1.start(); t2.start(); t3.start(); |
1.12、线程组中不可控异常的处理
public class Task implements Runnable {
@Override public void run() { Random random=new Random(Thread.currentThread().getId()); while (true) { int result=1000/((int)(random.nextDouble()*1000)); if (Thread.currentThread().isInterrupted()) { System.out.printf("%d : Interrupted\n",Thread.currentThread().getId()); return; } } } }
public class MyThreadGroup extends ThreadGroup {
public MyThreadGroup(String name) { super(name); }
@Override public void uncaughtException(Thread t, Throwable e) { interrupt(); } }
public class Main {
public static void main(String[] args) {
MyThreadGroup threadGroup=new MyThreadGroup("MyThreadGroup"); Task task=new Task(); for (int i=0; i<2; i++){ Thread t=new Thread(threadGroup,task); t.start(); } }
} |
1.13、使用工厂类创建线程
public class Task implements Runnable {
@Override public void run() { System.out.println(Thread.currentThread().getName()); }
} |
public class MyThreadFactory implements ThreadFactory {
private int counter; private String name;
public MyThreadFactory(String name){ counter=0; this.name=name; }
@Override public Thread newThread(Runnable r) { Thread t=new Thread(r,name+"-Thread_"+counter); counter++; return t; }
} |
public class Main {
public static void main(String[] args) { MyThreadFactory factory=new MyThreadFactory("MyThreadFactory"); Task task=new Task();
for (int i=0; i<110; i++){ Thread thread = factory.newThread(task); thread.start(); }
}
} |