首页 » java » 正文

重学java(四)

线程的休眠过程中可能会被其他线程打断,所以要捕获InterruptedException异常。

继承的话,this即是当前线程,Runnable则是Thread.currentThread()方法。

因为Runnable只有一个方法,所以可以直接用Lambda表达式来搞。

Thread.sleep()直接就是当前线程等待。

Timer类可以每隔一段时间执行,方法是:
schedule(TimerTask task, long delay, long preiod);
TimerTask是实现了Runnable的一个类,可以覆盖run接口,第二个参数是第一次执行前要等待的时间,第三个参数是每个执行的间隔。

import static java.lang.System.*;
public class CalendarDate8 {
    public static void main(String args[]){
        Timer timer= new Timer();
        MyTask myTask = new MyTask();
        timer.schedule(myTask, 1000, 1000);
    }
}
class MyTask extends TimerTask{
    public void run(){
        out.println("TimerTask...");
    }
}

线程比较好用的点就是各干各的。

import static java.lang.System.*;
public class CalendarDate8 {
    public static void main(String args[])throws Exception{
        final URL[] urls = {
                new URL("http://www.baidu.com"),
                new URL("http://www.pku.edu.cn"),
                new URL("http://sina.com.cn"),
                new URL("http://www.dstang.com")};
        final String[] files = {"baidu.htm","pku.htm", "sina.com.cn","dstang.com"};
        for(int i=0; i<urls.length; i++){
            final int idx = i;
            new Thread(()->{
                try{
                    out.println(urls[idx]);
                    download(urls[idx], files[idx]);
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }).start();
        }
    }
    static void download(URL url, String file)throws Exception{
        try(InputStream input = url.openStream();
            OutputStream output = new FileOutputStream(file)) {
            byte[] data = new byte[1024];
            int length;
            while ((length = input.read(data)) != -1) {
                output.write(data, 0, length);
            }
        }

    }
}

线程的状态
1. 新建
2. 就绪,进入线程队列排队等待cpu时间片。
3. 运行。就绪状态的线程获得时间片就进入运行状态,执行run方法。
4. 阻塞。人为挂起,输入输出等。
5. 终止。正常执行完毕或者是执行destroy终止线程。

以前可以通过调用stop来停止线程,现在不推荐使用,而是采用设置标记变量的方法来决定线程是否终止。

import static java.lang.System.*;
public class CalendarDate8 {
    public static void main(String args[])throws Exception{
        Timer timer = new Timer();
        Thread thread=new Thread(timer);
        thread.start();
        for(int i=1; i<=100; i++){
            out.println("\r"+i);
            try{
                Thread.sleep(1000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        timer.stopRun();
    }
}

class Timer implements Runnable{
    boolean flag = true;
    public void run(){
        while(flag){
            out.println("\t\t"+new Date() +"...");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        out.println("\n"+Thread.currentThread().getName()+"Stop.");
    }
    public void stopRun(){
        flag = false;
    }
}

sleep方法,停止一段时间。

join(),调用某线程对象的join()方法,可以把另一线程加入本线程中,本线程的执行会等待另一线程执行完毕才执行。

import static java.lang.System.*;
public class CalendarDate8 {
    public static void main(String args[])throws Exception{
        MyRun myRun = new MyRun();
        Thread thread = new Thread(myRun);
        thread.start();
        thread.join();
        out.println("主线程...");
    }
}

class MyRun implements Runnable{
    public void run(){
        try{
            Thread.sleep(10000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        out.println("子线程执行...");
    }
}

注意是当前线程等待,可以在join中加个long类型的参数,表示等待的最长时间。

yield(意思为放弃):作用是把当前线程让出cpu,放到就绪状态。

Thread类有三个优先级常量:MIN_PRIORITY(值为1)、MAX_PRIORITY(值为10)、NORM_PRIORITY(值为5)。

新线程的优先级将得到父进程的优先级。

一般主线程具有普通优先级。

设置优先级方法:setPriority(int priority)

后台线程(守护线程):daemon线程。

若还有非后台线程,则程序不会停止。

将一个线程设为守护进程的方法是setDaemon(true);

所有线程独立、异步执行。

由于多线程同时操作一个对象引起的现象,称为该对象不是线程安全的。

对特殊的资源-内存,java提供了内建的机制来防止他们的冲突,即使用synchronized(意思为同步的)。

在任何时刻,都只能有一个线程调用特定对象的一个synchronized方法.

每个对象都有一把锁(也叫做”监视器”),它自动成为对象的一部分,调用对象的任何synchronized方法,对象就会被锁定,不可再调用那个对象的其他任何synchronized方法。方法执行完毕,锁解除。

对象的所有方法共享一把锁。

每个类也有自己的锁,静态方法共享一把锁,如果不是很理解,可以看传送门.

private字段可以通过synchronized方法同步,但是其他的不行。

synchronized除了可以放在方法名前面,还能用在方法内部,
synchronized(对象){
…语句;
}
这里表示在语句执行期间,给对象加锁。

被多个需同步的线程共享的对象称为条件变量

监视器及notify wait综合使用:

import static java.lang.System.*;
public class CalendarDate8 {
    public static void main(String args[])throws Exception{
        CubbyHole cubbyHole=new CubbyHole();
        Producer producer=new Producer(cubbyHole,1);
        Producer producer1=new Producer(cubbyHole,2);
        Consumer consumer=new Consumer(cubbyHole,1);
        Consumer consumer1=new Consumer(cubbyHole, 2);
        producer.start();
        consumer.start();
    }
}
class Producer extends Thread{
    private CubbyHole cubbyHoles;
    private int number;
    public Producer(CubbyHole c, int number){
        cubbyHoles=c;
        this.number=number;
    }
    public void run(){
        for(int i=0; i<10; i++){
            cubbyHoles.put(i);
            out.println("Producer # "+this.number + " put"+i);
            try{
                sleep((int)(Math.random()*100));
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
class Consumer extends Thread{
    private CubbyHole cubbyHole;
    private int num;
    public Consumer(CubbyHole c, int number){
        cubbyHole=c;
        this.num=number;
    }
    public void run(){
        int value=0;
        for(int i=0; i<10; i++){
            value=cubbyHole.get();
            out.println("Comsumer # "+this.num + " got:"+value);
        }
    }
}
class CubbyHole{
    private int seq;
    private boolean available=false;
    public synchronized int get(){
        while(available == false){
            try{
                wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        available=false;
        notify();
        return seq;
    }
    public synchronized void put(int value){
        while(available==true){
            try{
                wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        seq=value;
        available=true;
        notify();
    }
}

死锁的处理有时间深入学习一下。

Iterator不是线程安全的,在使用的时候需要synchronized。

CopyOnwriteArrayList及CopyOnWriteSet分别实现了List接口和set接口,对于很少进行写入、而使用迭代器频繁的,可以使用这两个类。

BlockingQueue接口及其实现类ArrayBlockingQueue、LinkedBlockingQueue实现了Queue接口并增加了两个方法:
take()方法在获取时要等待队列变成非空,put在存储时要等待有空闲空间。

ConcurrentMap接口的putIfAbsent(),remove(),replace()等方法,都是线程安全的。实现类有ComcurrentHashMap、ComcurrentSkipListMap分别对应HashMap和TreeMap。其中Comcurrent是并发的意思。

import static java.lang.System.*;
public class CalendarDate8 {
    public static void main(String args[])throws Exception{
        BlockingQueue<Integer> queue =new ArrayBlockingQueue<>(1);
        new Thread(new Producer(queue)).start();
        new Thread(new Comsumer(queue)).start();
    }
}

class Producer implements Runnable{
    private BlockingQueue<Integer>queue;
    public Producer(BlockingQueue<Integer> queue){
        this.queue=queue;
    }
    public void run(){
        for(int i=0; i<10; i++){
            try{
                Thread.sleep((int)(Math.random()*10));
                queue.put(i);
                out.println("生产:"+i);
            }catch (InterruptedException e){

            }
        }
    }
}

class Comsumer implements Runnable{
    private BlockingQueue<Integer> queue;
    public Comsumer(BlockingQueue<Integer> queue){
        this.queue=queue;
    }
    public void run(){
        for(int i=0; i<10; i++){
            try{
                Thread.sleep((int)(Math.random()*10));
                Integer integer = queue.take();
                out.println("消费:"+integer);
            }catch (InterruptedException e){

            }
        }
    }
}

java变量前面加个volatile,读取会直接从内存读取。

一个n++包含三个操作(取数据、增加、放回),原子变量解决这个问题,保证其全部执行或全部不执行,而不是执行一半被其他线程读到数据。
AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。

读写锁:ReentrantReadWriteLock类,reentrant为可重入的意思。

public class CalendarDate8 {
    ReadWriteLock lock=new ReentrantReadWriteLock();
    private Object[] list;
    private int next;  
    public static void main(String[] args) {
        CalendarDate8 ary = new CalendarDate8();  
    }
    public CalendarDate8(int capacity){
        list = new Object[capacity];  
    }
    public CalendarDate8(){
        this(16);  
    }
    public void add(Object o){
        try{
            lock.writeLock().lock();
            if(next == list.length){
                list= Arrays.copyOf(list, list.length*2);
            }
            list[next++]=o;  
        }finally {
            lock.writeLock().unlock();
        }
    }

    public Object get(int index){
        try{
            lock.readLock().lock();
            return list[index];  
        }finally {
            lock.readLock().unlock();
        }
    }

    public int size(){
        try{
            lock.readLock().lock();
            reurn next;  
        }finally {
            lock.readLock().unlock();
        }
    }
}

Executor接口表示线程的执行过程(包括利用线程池),Future则提供了异步操作的可能。

Executor的execute(Runnable command)方法用来执行已提交的Runnable任务。

线程池一般的方式是使用ThreadPoolExecutor类(实现了Executor接口),另外用Executors类的newCachedThreadPool()或newFixedThreadPool()方法可以得到具有线程池的Executor。

线程池可以循环的使用以分配好的线程,而不用每次都创建新的线程,用完的线程又放回到线程池。

Callable接口类似Runnable接口,但是它具有返回值,Callable\< T >的方法是\< T >call().

EXecutorService的submit方法可以提交一个Callable的任务,并得到一个Future对象。

Future接口表示异步计算的结果。它提供了检查计算的完成,并获取计算的结果。可以使用get方法获取结果。

如有计算没完成会阻塞到计算完成或取消。cancel()方法可以取消。

import static java.lang.System.*;
public final class Main{
    public static void main(String args[]){
        ExecutorService executor = Executors.newCachedThreadPool();
        out.println("准备计算:");
        Future<Long> future = executor.submit(new Callable<Long>() {
            @Override
            public Long call() throws Exception {
                return fibonacci(45);
            }
        });
        out.println("主线程可以执行其他的事...");
        try{
//            Thread.sleep(2000);
            out.println("异步计算结果:");
            out.println(future.get());
            executor.shutdown();//结束线程池
        }catch (InterruptedException| ExecutionException e){
            e.printStackTrace();
        }
    }
    static long fibonacci(int n){
        if(n==0 || n==1) return 1;
        else return fibonacci(n-1)+fibonacci(n-2);
    }
}

发表评论