1.线程及启动和终止
1.1 线程 -进程/优先级
操作系统调度的最小单元是线程,线程是轻量级进程。
线程优先级由setPriority(int)方法来设置,默认优先级是5,等级1~10.等级越高分的时间片越多。
1.2 线程的状态
new 初始化 》》Runable 运行》》Blocked阻塞 》》Wating等待》》 time_Wating超时等待》》 temerinated终止状态。
1.3 Daemon辅助线程
主线程终止后,辅助线程也就结束。thread.setDaemon(true)设置在线程开始之前。
1.4 过期suspend() , resume(), stop()为啥不建议使用?
suspend()调用后太霸道,不释放占有资源,而是抱着占有资源去睡觉,这样容易死锁。站着茅坑不拉屎。
resume()、stop()不保证线程资源正常释放,那要你们何用?
安全的终止线程:有中断操作,和自定义cancel()方法。
1 package Thread; 2 3 import java.util.concurrent.TimeUnit; 4 5 /** 6 * Created by Sky on 2016/9/22. 7 * @author xiaoyongyong 8 */ 9 public class Shutdown { 10 public static void main(String[] args) throws InterruptedException { 11 Runner one = new Runner(); 12 Thread countThread = new Thread(one,"CountThread"); 13 countThread.start(); 14 TimeUnit.SECONDS.sleep(1); 15 countThread.interrupt(); 16 17 Runner two = new Runner(); 18 countThread = new Thread(two,"CountThread"); 19 countThread.start(); 20 TimeUnit.SECONDS.sleep(1); 21 two.cancle(); 22 } 23 24 private static class Runner implements Runnable{ 25 private long i; 26 private volatile boolean on =true; 27 @Override 28 public void run() { 29 while (on && !Thread.currentThread().isInterrupted()){ 30 i++; 31 } 32 System.out.println("Count i ="+ i); 33 } 34 public void cancle(){ 35 on = false; 36 } 37 } 38 }
2. 线程之间通信
2.1 volatile 和 synchronized 关键字。
volatile:它能保证所有线程对变量访问的可见性,即某线程对定义变量的修改,其他线程可见。谨慎使用,过多使用会降低程序运行效率。
syncchronized:保证只有一个线程能对其定义的变量修改。保证其变量访问的可见性和排他性。
2.2 通知/等待机制
可以确保及时性和降低开销。
相关方法:notify()、nitifyAll()、wait()、wait(long)、wait(long,int)。
注意点:1)使用notify()、nitifyAll()、wait()时需要先对调用对象加锁。2)notify()、nitifyAll()方法调用后,等待线程依旧不会从wait()方法返回,
需要调用notify()、nitifyAll()方法的线程,释放锁之后,等待线程才有机会从wait()返回。等待队列-》同步队列。3)wait()方法返回的前提是获取对象锁。
这种机制可以运用在生产者-消费者模式中。
1 package Thread; 2 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.concurrent.TimeUnit; 6 7 /** 8 * Created by Sky on 2016/9/22. 9 * 10 * @author xiaoyongyong 11 */ 12 public class WaitNotify { 13 static boolean flag = true; 14 static final Object lock = new Object(); 15 16 public static void main(String[] args) throws Exception { 17 Thread waitTread = new Thread(new Wait(), "WaitTread"); 18 waitTread.start(); 19 TimeUnit.SECONDS.sleep(1); 20 21 Thread notifyTread = new Thread(new NotifyTread(), "NotifyTread"); 22 notifyTread.start(); 23 } 24 25 private static class Wait implements Runnable { 26 @Override 27 public void run() { 28 synchronized (lock) { 29 while (flag) { 30 try { 31 System.out.println(Thread.currentThread() + " flag is true.wait. " + new SimpleDateFormat("HH:mm:ss").format(new Date())); 32 lock.wait(); 33 } catch (InterruptedException e) { 34 e.printStackTrace(); 35 } 36 } 37 System.out.println(Thread.currentThread() + " flag is true.running. " + new SimpleDateFormat("HH:mm:ss").format(new Date())); 38 } 39 } 40 } 41 42 private static class NotifyTread implements Runnable { 43 @Override 44 public void run() { 45 synchronized (lock){ 46 System.out.println(Thread.currentThread() + " hold lock.notify. " + new SimpleDateFormat("HH:mm:ss").format(new Date())); 47 lock.notifyAll(); 48 flag = false; 49 try { 50 TimeUnit.SECONDS.sleep(2); 51 } catch (InterruptedException e) { 52 e.printStackTrace(); 53 } 54 } 55 synchronized (lock) { 56 System.out.println(Thread.currentThread() + " hold lock.again.sleep " + new SimpleDateFormat("HH:mm:ss").format(new Date())); 57 try { 58 TimeUnit.SECONDS.sleep(2); 59 } catch (InterruptedException e) { 60 e.printStackTrace(); 61 } 62 } 63 } 64 } 65 }
返回结果:
Thread[WaitTread,5,main] flag is true.wait. 22:03:45
Thread[NotifyTread,5,main] hold lock.notify. 22:03:46
Thread[NotifyTread,5,main] hold lock.again.sleep 22:03:48
Thread[WaitTread,5,main] flag is true.running. 22:03:50
2.3 管道输入/输出流
主要用于线程之间的数据传输,传输媒介是内存,有PipedOutputStream/PipedInputStream(面向字节) 和PipedReader/PipedWriter(面向字符)。
1 package Thread; 2 3 import java.io.IOException; 4 import java.io.PipedReader; 5 import java.io.PipedWriter; 6 7 /** 8 * Created by Sky on 2016/9/22. 9 * @author xiaoyongyong 10 */ 11 public class Piped { 12 public static void main(String[] args) throws IOException { 13 PipedWriter out = new PipedWriter(); 14 PipedReader in = new PipedReader(); 15 out.connect(in); 16 Thread printThread = new Thread(new Print(in), "PringThread"); 17 printThread.start(); 18 19 int receive; 20 try { 21 while ((receive = System.in.read()) != -1) { 22 out.write(receive); 23 } 24 } finally { 25 out.close(); 26 } 27 } 28 29 private static class Print implements Runnable { 30 private PipedReader in; 31 public Print(PipedReader in) { 32 this.in = in; 33 } 34 @Override 35 public void run() { 36 int receive; 37 try { 38 while ((receive = in.read()) != -1) { 39 System.out.print((char) receive); 40 } 41 } catch (IOException e) { 42 e.printStackTrace(); 43 } 44 } 45 } 46 }
输入一串字符串,按enter后,将原样输出。管道输入输出流必须先连接才可复制,即connect()。
2.4 Thread.join()的使用
当线程A等待thread线程终止之后,才从thread.join()返回。
join方法顾名思义 就是往线程中添加东西的;join方法可以用于临时加入线程,一个线程在运算过程中,如果满足于条件,我们可以临时加入一个线程,让这个线程运算完,另外一个线程再继续运行。
Thread,yeld()和Thread.sleep()的区别?
hread.yield()方法暂停当前正在执行的线程对象,并执行其他线程。也就是交出CPU一段时间(其他同样的优先级或者更高优先级的线程可以获取到运行的机会);不会释放锁资源。
而Thread.sleep()方法使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行, 同时sleep函数不会释放锁资源;sleep可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会。
这两个的区别在于yield只能是同级,或者高级优先执行,而sleep可以低级,同级都可以有优先执行机会。
2.5 ThreadLocal的使用
线程变量,是一个以TreadLocal对象为键,任意对象为值得存储结构。
2.6 线程池技术及示例。
以下是线程池接口的定义和实现:
package Thread; /** * Created by asus on 2016/9/27. */ public interface ThreadPool<Job extends Runnable> { void execute(Job job); void shutdown(); void addWorkers(int num); void removeWoker(int num); int getJobSize(); }
package Thread; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; /** * Created by asus on 2016/9/27. * * @author xiaoyongyong */ public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> { private static final int MAX_WORKER_NUMBERS = 10; private static final int DEFAULT_WORKER_NUMBERS = 5; private static final int MIN_WORKER_NUBERS = 1; private final LinkedList<Job> jobs = new LinkedList<Job>(); private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>()); private int workerNum = DEFAULT_WORKER_NUMBERS; private AtomicLong threadNum = new AtomicLong(); public DefaultThreadPool() { initializeWorker(DEFAULT_WORKER_NUMBERS); } private void DefaultThreadPool(int num) { workerNum = num > MAX_WORKER_NUMBERS ? MAX_WORKER_NUMBERS : num < MIN_WORKER_NUBERS ? MAX_WORKER_NUMBERS : num; initializeWorker(workerNum); } @Override public void execute(Job job) { if (job != null) { synchronized (jobs) { jobs.add(job); jobs.notify(); } } } @Override public void shutdown() { for (Worker worker : workers) { worker.shutdown(); } } @Override public void addWorkers(int num) { synchronized (jobs) { if (num + this.workerNum > MAX_WORKER_NUMBERS) { initializeWorker(num); this.workerNum += num; } } } @Override public void removeWoker(int num) { synchronized (jobs) { if (num >= this.workerNum) { throw new IllegalArgumentException("beyond workerNum"); } int count = 0; while (count < num) { Worker worker = workers.get(count); if (workers.remove(worker)) { worker.shutdown(); count++; } } this.workerNum -= count; } } @Override public int getJobSize() { return jobs.size(); } private void initializeWorker(int num) { for (int i = 0; i < num; i++) { Worker worker = new Worker(); workers.add(worker); Thread threadWorker = new Thread(worker, "ThreadPool-Worker-" + threadNum.incrementAndGet()); threadWorker.start(); } } class Worker implements Runnable { private volatile boolean running = true; @Override public void run() { while (running){ Job job = null; synchronized (jobs){ while (jobs.isEmpty()){ try { jobs.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); return; } } job = jobs.removeFirst(); } if(job != null){ job.run(); } } } public void shutdown() { running = false; } } }
2.7 基于县此次技术的简单Web服务器
这个服务器使用main线程不断接受客户端Socket的连接,将连接以及请求交给线程池处理,这样使得Web服务器能够同同时处理多个客户端请求。