线程池、线程安全

线程的匿名内部类

  匿名内部类对象格式:

    new 父类类型(){

      抽象父类的方法、
    }
    最终得到的就是父类类型的子类对象

  有两种方式,1:创建线程对象时,直接重写Thread类中的run方法

1 // 继承thread//创建线程任务和线程对象    
2         new Thread(){
3             public void run() {                
4                 for (int i = 0; i <100; i++) {
5                     System.out.println(Thread.currentThread().getName()+":"+i);
6                 }
7             }
8         }.start();

        2:使用匿名内部类的方式实现Runnable接口,重新Runnable接口中的run方法

Runnable r=new Runnable(){
            public void run(){
                for (int i = 0; i <100; i++) {
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
            }
        };
        //创建线程对象
        Thread t=new Thread(r);
        //开启线程
        t.start();

线程池

  为了避免重复的创建线程,线程池的出现可以让线程进行复用。通俗点讲,当有工作来,就会向线程池拿一个线程,当工作完成后,并不是直接关闭线程,而是将这个线程归还给线程池供其他任务使用。

  线程池的使用我们主要是通过Runnable接口、Callable接口来实现;

  Runnable接口的使用:

    1.从线程池工厂(Executor)对象中获取线程池(ExecutorService)对象

    2.让线程池对象从池子中选一条空闲的线程执行线程任务,没有等待,用完放回

    3.没有对象销毁线程池

1         MyRunnable mr=new MyRunnable();
2         ExecutorService es=Executors.newFixedThreadPool(2);
3         ExecutorService es2=Executors.newFixedThreadPool(10);
4         es.submit(mr);
5         es.submit(mr);
6         es.submit(mr);
7         es2.submit(mr);
8         es.shutdown();
9         es2.shutdown();

  Callable接口的使用:

    与Runnable接口功能相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常。

    这里讲一下Future接口,他用来记录线程任务执行完毕后产生的结果。线程池创建与使用,Runnable接口和Callable接口都可以使用。

    例:

 1 //创建线程任务
 2         MyCallable mc=new MyCallable();
 3         //获取线程池对象
 4         ExecutorService es=Executors.newFixedThreadPool(2);
 5         //获取future对象
 6         Future<String> f = es.submit(mc);
 7         //从future对象中获取返回值
 8         String s=f.get();
 9         System.out.println(s);
10         //销毁线程池
11         es.shutdown();

  MyCallable.java:

    

   运行之后得到的是返回值

 线程安全

  当若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

  线程同步的方式有两种:一是同步代码块,二是同步方法;

  同步代码块:在代码块声明上 加上synchronized

    基本格式:

      synchronized(非匿名的任意对象){

            线程要操作的共享数据

      }

    例:

 1 //创建锁对象
 2     private Object obj=new Object();
 3     public void run() {
 4         while(true){
 5             synchronized (obj) {
 6                 
 7             
 8         if (ticket>0) {
 9             try {
10                 Thread.sleep(300);
11             } catch (InterruptedException e) {
12                 // TODO Auto-generated catch block
13                 e.printStackTrace();
14             }
15             System.out.println(Thread.currentThread().getName()+"窗口卖了第"+ticket--+"张票");
16         }
17     }
18     }
19     }

    synchronized(obj)中的obj相当于是一个同步锁,没有get到锁的线程不能进入同步,在同步中的线程如果没有运行到synchronized的最后,则不会释放锁

    另外,加上了线程同步之后,程序的运行速度会明显减慢

  同步方法(推荐)
    将线程共享数据,同步,抽取到一个方法中,在方法的声明处加入同步关键字
    省去synchronized中的 非匿名任意对象,而这个obj对象由本类对象引用this隐式代替,只是没有写出来而已。
 
    基本格式:
      public synchronized void method(){

           可能会产生线程安全问题的代码

      }

   Lock接口

    提供了获得锁lock()和释放锁unlock()两个方法
    基本步骤:
      1.创建lock对象
      2.获取锁
      3.可能会产生线程安全问题的代码
      4.释放锁
    
    
    

  

原文地址:https://www.cnblogs.com/zhai113/p/11780863.html