Java -- 线程
1. 创建线程(一)
定义线程类, 继承Thread 并重写run(), run()称为线程体。
单继承限制,尽量少用。
class firstThread extends Thread {
}
public class main {
}
创建线程(二)
实现接口Runnable, 并将其对象传入 Thread构造函数,生成Thread对象。
class RunnableImpl implements Runnable{
}
public class main {
}
两种方法对比:
继承Thread类: 编写简单,不必使用Thread.currentThread(),直接this.getName()即可。 但是不能再继承其他类了。。
实现Runnable接口: 可再继承其他类,可以多线程共享一个目标对象,但是编写略复杂,访问当前线程需要用Thread.currentThread()。
2. Join 线程等待
public class Main extends Thread{ private int i; public Main(String name) { super(name); } public void run() { for(; i<100; i++) { System.out.println(getName() + " " + i); } } public static void main(String[] args) throws InterruptedException { Main thread1 = new Main("1"); Main thread2 = new Main("2"); for(int i=0; i<100; i++) { if( i==20 ) { thread1.start(); thread1.join(); //一直阻塞到线程1结束 thread2.start(); } } } }
3. 后台线程 (守护线程) : JVM垃圾回收线程就是典型的后台线程,如果所有的前台线程都死亡,后台线程会自动死亡。
调用Thread对象的setDaemon(true)则可以设置线程为后台线程。
例如上面的 thread1.setDaemon(true); 即可。。
4. 线程让步 和 优先级设置
使用Thread的静态方法 Thread.yield()即可, 让步后线程并不是进入阻塞态,而是进入就绪态 重新竞争。
设置线程优先级可以用 thread1.setPriority(int ...) ; 输入参数可以为 MAX_PRIORITY 值为10, MIN_PRIORITY 1, NORM_PRIORITY 5.
5. 同步代码块 synchronized
可以使用同步代码块,锁定临界资源 synchronized(Object obj){... ....}
public void run()
{
Integer i;
for(i=0; i<100; i++)
{
synchronized(i) //同步代码块
{
System.out.println(getName() + " " + i);
}
}
}
还可以用synchronized 修饰类的方法,让该方法变为线程安全。
例如 public synchronized void draw() { ... ... }
6. 同步锁 ReadWriteLock(读写锁) ReentrantLock(可重入锁)
class A { private final ReentrantLock lock = new ReentrantLock(); //定义锁对象 public void fun() { lock.lock(); //加锁 try { // 需要 线程安全的代码 } finally { lock.unlock(); //解锁 } } }
7.线程通信
利用wait() 当前线程等待 notify()唤醒在同步监视器上等待的单个线程。 notifyAll()唤醒在同步监视器上的所有线程。
class A //属性 num 加一 减一 { private Boolean putflag = false; private Integer num = 0; public synchronized void get() { try { if( !putflag ) { wait(); //阻塞 } else { num--; System.out.println(Thread.currentThread().getName() + " get " + num); putflag = false; notifyAll(); //唤醒 } } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void put() { try { if( putflag ) { wait(); } else { num++; System.out.println(Thread.currentThread().getName() + " put " + num); putflag = true; notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } } class Get extends Thread { private A a; private String name; public Get(String name, A a) { this.name = name; this.a = a; } public void run() { for(int i=0; i<10; i++) { System.out.println(name); a.get(); //减一 } } } class Put extends Thread { private A a; private String name; public Put(String name,A a) { this.name = name; this.a = a; } public void run() { for(int i=0; i<10; i++) { System.out.println(name); a.put(); //加一 } } } public class Main extends Thread{ public static void main(String[] args) { A a = new A(); new Get("lisi", a).start(); new Put("wangwu", a).start(); new Put("zhangsan", a).start(); } }
输出效果是 加一 减一 交替进行。
如果不是用synchronized来保证同步的,如果是用lock, 可以用Condition来做协调
如下只需修改Class A
class B { private final Lock lock = new ReentrantLock(); //定义一个锁 lock private final Condition cond = lock.newCondition(); //定义 Condition public void put() { lock.lock(); try { if( !flag ) { cond.await(); //阻塞 } else { .... ..... cond.signalAll(); //唤醒 } } } }
使用管道线程间通信
管道字节流: PiedInputStream PieOutputStream 管道字符流: PipedReader PipedWriter 新IO管道Channel: Pipe.SinkChannel PipeSourceChannel
class ReaderThread extends Thread { private PipedReader pr; //输入管道 private BufferedReader br; public ReaderThread(PipedReader pr) { this.pr = pr; this.br = new BufferedReader(pr); } public void run() { String buf = null; try { while( (buf=br.readLine()) != null ) { System.out.println("Reader: " + buf); } } catch (IOException e) { e.printStackTrace(); } finally { try { br.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class WriterThread extends Thread { String[] strs = new String[]{ "1234", "5678", "qwer", "asdf" }; private PipedWriter pw; //写管道 public WriterThread(PipedWriter pw) { this.pw = pw; } public void run() { try { for(int i=0; i<10; i++) { pw.write(strs[i%4] + "\n"); System.out.println("Writer" + strs[i%4]); } } catch(IOException e) { e.printStackTrace(); } finally { try { pw.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public class Main extends Thread{ public static void main(String[] args) { PipedReader pr = null; PipedWriter pw = null; try { pw = new PipedWriter(); pr = new PipedReader(); pw.connect(pr); //管道连接 new WriterThread(pw).start(); //开启读写线程 new ReaderThread(pr).start(); } catch(IOException e) { e.printStackTrace(); } } }