多线程那些事(一)

1.线程创建的几种方式?

  • extends Thread类,重写run()方法
  • implements Runnable接口,重写run()方法
  • 利用线程池:Excutors

//固定数量的线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
//单任务线程池
ExecutorService pool = Executors.newSingleThreadExecutor();
//可变线程池
ExecutorService pool = Executors.newCachedThreadPool();
//定时线程池
ScheduledExecutorService pool= Executors.newScheduledThreadPool(2);
  • 利用ExecutorService、Callable、Future 实现有返回结果的多线程
/**
 * @program: demo
 * @description: ${description}
 * @author: Will Wu
 * @create: 2018-12-06 20:00
 **/
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class MyCallable implements Callable <Object>{

    private String taskNum;
    @Override
    public Object call() throws Exception {
        log.info("=======>"+taskNum+" 任务启动...");
        Date date1 = new Date();
        Thread.sleep(1000);
        Date date2= new Date();
        long time=date2.getTime()-date1.getTime();
        log.info("=======>"+taskNum+" 任务结束...");
        return taskNum+"任务返回运行结果,当前任务时间耗时:" + time+"毫秒";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        log.info("程序开始运行...");
        Date date = new Date();
        int size=5;
        ExecutorService pool = Executors.newFixedThreadPool(size);
        ArrayList<Future> list = new ArrayList<>();
        for(int i=0;i<size;i++){
            MyCallable callable = new MyCallable(i + "");
            Future<Object> future = pool.submit(callable);
            log.info(future.get().toString());
            list.add(future);
        }
        pool.shutdown();
        list.stream().collect(Collectors.toList()).forEach(System.out::println);

    }
}

2.wait()和sleep()方法的区别

  • 最大的区别在于sleep方法并没有释放锁,wait方法释放了锁;

  • 所以sleep方法一般用于暂停执行的场景,wait则通常用于线程加交互;

3.synchronized 和 volatile 关键字的作用

  • 就我个人理解而言,synchronized关键字主要是锁定当前变量,只允许当前线程访问该变量,其他变量处于阻塞状态;而volatile关键字,保证了不同线程对该变量进行操作的可见性,即一个线程修改了某变量,修改后的新值对于其他线程来说是立即可见的
  • synchronized关键字可以用在代码块,方法和变量上,volatile关键字只能用于变量上

4. java内存模型中线程运行机制

在java内存模型中,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时变量的相关信息,当线程访问某个对象的时候,首先通过对象的引用找到对应堆内存的变量的值,然后把堆内存里该变量的具体值加载到线程本地内存,建立一个变量副本,之后线程就不在跟对象的堆内存变量值有任何联系,而是直接修改副本变量的值,修改完之后,自动把线程变量副本的值同步到堆内存中该变量的值,从而该变量的值发生了变化

5.如何控制某个方法允许并发访问线程的个数?

/**
 * @program: demo
 * 如何控制某个方法允许并发访问线程的个数
 * @description: ${description}
 * @author: Will Wu
 * @create: 2018-12-08 10:06
 **/
public class SeamphoreTest {

    //采用该Semaphore类,如下代码去控制test()方法最多五个线程并发访问
    static Semaphore semaphore=new Semaphore(5,true);

    public static void main(String[] args) {
        for(int i=0;i<100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    test();
                }
            }).start();
        }
    }

    public static void test(){
        try {
            //申请一个请求
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName()+"is coming...");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"is going...");

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        semaphore.release();

    }
}

 

猜你喜欢

转载自blog.csdn.net/wuyundong123/article/details/84890067