一、线程的理解
1、同个应用中,多个任务同时进行。就像QQ聊天,打开一个聊天窗口就是一个线程。
2、线程可以有多个,但cpu每时每刻只做一件事。由于cpu处理速度很快,我们就感觉是同时进行的。所以宏观上,线程时并发进行的;从微观角度看,线程是异步执行的。
3、使用线程的目的是最大限度的利用cpu资源。想想QQ聊天的时候,如果没有多线程,一个人的信息没有发完另一个人的信息发不过来,会是什么情况~!
二、java中使用线程
1、创建线程
eg1:继承Thread
class MyThread extends Thread{ @Override public void run() { //code } }
启动线程方法:new MyThread().start();
eg2:实现Runnable接口
class MyRunnable implements Runnable { @Override public void run() { //code } }
启动线程方法:new Thread(new MyRunnable()).start();
2、设置线程优先级
Thread t = new Thread(myRunnable); t.setPriority(Thread.MAX_PRIORITY);//一共10个等级,Thread.MAX_PRIORITY表示最高级10
t.start();
3、join,sleep,yield的用法与区别
join方法:假如你在A线程中调用了B线程的join方法B.join();,这时B线程继续运行,A线程停止(进入阻塞状态)。等B运行完毕A再继续运行。
sleep方法:线程中调用sleep方法后,本线程停止(进入阻塞状态),运行权交给其他线程。
yield方法:线程中调用yield方法后本线程并不停止,运行权由本线程和优先级不低于本线程的线程来抢。(不一定优先级高的能先抢到,只是优先级高的抢到的时间长)
4、结束线程(修改标示符flag为false来终止线程的运行)
public class ThreadTest { public static void main(String[] args) { A aa = new A(); Thread tt = new Thread(aa); tt.start(); try { Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } aa.shutDown(); } } class A implements Runnable { private boolean flag = true; public void run() { while (flag) { System.out.println("AAAA"); } } public void shutDown() { this.flag = false; } }
5、线程同步synchronized
synchronized可以修饰方法,或者方法内部的代码块。被synchronized修饰的代码块表示:一个线程在操作该资源时,不允许其他线程操作该资源。
public class ThreadTest { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); new Thread(myRunnable).start(); new Thread(myRunnable).start(); new Thread(myRunnable).start(); new Thread(myRunnable).start(); } } class MyRunnable implements Runnable { private int i = 0; @Override public void run() { while (true) { sumNum(); } } private synchronized void sumNum() { if (i < 100) { try { Thread.sleep(1000); i ++; } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "--------" + i); } } }
6、wait、notify、notifyAll的用法
wait方法:当前线程转入阻塞状态,让出cpu的控制权,解除锁定。
notify方法:唤醒因为wait()进入阻塞状态的其中一个线程。
notifyAll方法: 唤醒因为wait()进入阻塞状态的所有线程。
这三个方法都必须用synchronized块来包装,而且必须是同一把锁,不然会抛出java.lang.IllegalMonitorStateException异常。
下面是一个生产者、消费者例子:
public class ProductConsumer { public static int i = 0; public static void main(String[] args) { ProductStack ps = new ProductStack(); Product product = new Product(ps); new Thread(product).start(); Consumer consumer = new Consumer(ps); new Thread(consumer).start(); } } class Product implements Runnable { ProductStack ps = null; Product(ProductStack ps) { this.ps = ps; } @Override public void run() { while (true) { if (ProductConsumer.i < 100) { ps.push(); }else{ break; } } } } class Consumer implements Runnable { ProductStack ps = null; Consumer(ProductStack ps) { this.ps = ps; } @Override public void run() { while (true) { if (ProductConsumer.i < 100) { ps.pop(); }else{ break; } } } } class ProductStack { boolean isPro = true; public synchronized void push() { if (!isPro) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } notifyAll(); ProductConsumer.i++; System.out.print("第" + ProductConsumer.i + "个产品,生产者:" + Thread.currentThread().getName()); isPro = false; try { Thread.sleep((int) Math.random() * 200); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void pop() { if (isPro) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } notifyAll(); System.out.println(",消费者:" + Thread.currentThread().getName()); isPro = true; try { Thread.sleep((int) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } }