关于java:牛啊牛啊这篇多线程技术笔记阿里架构师看了都说好

40次阅读

共计 6957 个字符,预计需要花费 18 分钟才能阅读完成。

程序,过程,线程

  • 程序:为实现特定工作,应用某种语言编写的一组指令的汇合,是一段动态的代码。
  • 过程:程序的一次运行过程,或者是正在运行的一个程序。过程是资源分配的根本单位。
  • 线程:线程由过程进一步细化而来,是一个程序外部的一条执行门路。线程是调度和执行的单位,每个线程领有独立的运行栈和程序计数器,线程开销很小。

Thread 生命周期

Thread 类中的罕用办法

  • start():启动以后线程;调用以后线程的 run()。
  • run():通常须要重写 Thread 类中的此办法,将创立的线程要执行的操作申明在此办法中。
  • currentThread():静态方法,返回执行以后代码的线程。
  • getName():获取以后线程的名字。
  • setName():设置以后线程的名字。
  • yield():开释以后 cpu 的执行权。
  • join():在线程 a 中调用线程 b 的 join() 办法, 此时线程 a 就进入阻塞状态,直到线程 b 齐全执行完当前,线程 a 才完结阻塞状态。
  • sleep(long millitime):让以后线程“睡眠”指定的 millitime 毫秒。在指定的 millitime 毫秒工夫内,以后线程是阻塞状态。
  • isAlive():判断以后线程是否存活。
  • getPriority():获取线程的优先级。
  • setPriority(int p):设置线程的优先级。
  • 线程的优先级有以下三种,MAX_PRIORITY:10;MIN _PRIORITY:1;NORM_PRIORITY:5。

创立多线程的形式

继承 Thread 类

步骤:

  • 创立一个继承于 Thread 类的子类;
  • 重写 Thread 类中的 run() 办法,将次线程执行的操作申明在 run() 办法中。
  • 创立 Thread 类的子类对象。
  • 通过此对象调用 start()。

举例:三个窗口进行卖票(存在线程平安问题)

class MThread extends Thread{
    private static int tickets = 100;
    @Override
    public void run() {while(true){if(tickets > 0){System.out.println(getName() + "卖票,票号为:" + tickets--);
            }else{break;}
        }
    }
}
public class ThreadTest {public static void main(String[] args) {MThread t1 = new MThread ();
        MThread t2 = new MThread ();
        MThread t3 = new MThread ();
        t1.setName("窗口 1");
        t2.setName("窗口 2");
        t3.setName("窗口 3");
        t1.start();
        t2.start();
        t3.start();}
}

阐明:局限于类的单继承性。

实现 Runnable 接口

步骤:

  • 创立一个实现 Runnable 接口的类。
  • 实现类去实现 Runnable 中的形象办法:run()。
  • 创立实现类的对象。
  • 将此对象作为参数传递到 Thread 类的结构器中,创立 Thread 类的对象。
  • 通过 Thread 类的对象调用 start()。

举例:三个窗口进行卖票(存在线程平安问题)

class MThread implements Runnable{
   private int tickets = 100;
   @Override
   public void run() {while(true){if(tickets > 0){System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + tickets--);
           }else{break;}
       }
   }
}
public class ThreadTest {public static void main(String[] args) {MThread m = new MThread();
       Thread t1 = new Thread(m);
       Thread t2 = new Thread(m);
       Thread t3 = new Thread(m);
       t1.setName("窗口 1");
       t2.setName("窗口 2");
       t3.setName("窗口 3");
       t1.start();
       t2.start();
       t3.start();}
}

阐明:不会局限于类的单继承性;适宜解决多个线程共享数据的状况。

实现 Callable 接口

步骤:

  • 创立一个实现 Callable 的实现类。
  • 实现 call 办法,将此线程须要执行的操作申明在 call() 中。
  • 创立 Callable 接口实现类的对象。
  • 将此 Callable 接口实现类的对象作为参数传递到 FutureTask 结构器中,创立 FutureTask 的对象。
  • 将 FutureTask 的对象作为参数传递到 Thread 类的结构器中,创立 Thread 对象,并调用 start()。

举例:遍历 100 以内的偶数,并且计算他们的和

class MThread implements Callable{
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 2; i < 101; i+=2) {System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}


public class ThreadTest {public static void main(String[] args) {MThread thread = new MThread ();
        FutureTask futureTask = new FutureTask(thread);
        new Thread(futureTask).start();
        try {//get() 返回值即为 FutureTask 结构器参数 Callable 实现类重写的 call() 的返回值。Object sum = futureTask.get();
            System.out.println("总和为:" + sum);
        } catch (InterruptedException e) {e.printStackTrace();
        } catch (ExecutionException e) {e.printStackTrace();
        }
    }

}

阐明:call() 办法有返回值,并且能够抛出异样;callable 反对泛型。

线程池

步骤:

  • 提供指定线程数量的线程池。
  • 执行指定的线程的操作。须要提供实现 Runnable 接口或 Callable 接口实现类的对象。
  • 敞开线程池。

举例:两个线程遍历 100 以内的奇偶数

class NumberThread implements Runnable{

    @Override
    public void run() {for(int i = 1;i < 101; i+=2){System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

class NumberThread1 implements Runnable{

    @Override
    public void run() {for(int i = 2;i < 101; i+=2){System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

public class ThreadPool {public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
        service.execute(new NumberThread());// 实用于 Runnable
        service.execute(new NumberThread1());// 实用于 Runnable

        //service.submit(Callable callable);// 应用于 Callable
        service.shutdown();}
}

阐明:进步了响应速度;升高资源耗费;便于线程治理。

线程同步机制

解决线程平安问题

同步代码块

synchronized(对象){// 须要被同步的代码}
举例:三个窗口卖票

class Windows extends Thread{
    private static int tickets = 100;
    @Override
    public void run() {while(true){synchronized(Windows.class){
                try {Thread.sleep(10);
                } catch (InterruptedException e) {e.printStackTrace();
                }
                if(tickets > 0){System.out.println(getName() + "卖票,票号为:" + tickets--);
                }else{break;}
            }
        }
    }
}
public class Test {public static void main(String[] args) {Windows t1 = new Windows();
        Windows t2 = new Windows();
        Windows t3 = new Windows();
        t1.setName("窗口 1");
        t2.setName("窗口 2");
        t3.setName("窗口 3");
        t1.start();
        t2.start();
        t3.start();}
}

同步办法

将 synchronized 放到办法的申明中。
举例:三个窗口卖票。

class Windows implements Runnable {
    private int tickets = 100;
    @Override
    public void run() {while(true){show();
        }
    }
    private synchronized void show(){if(tickets > 0){
            try {Thread.sleep(10);
            } catch (InterruptedException e) {e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + tickets--);
        }
    }

}
public class Test{public static void main(String[] args) {Windows t = new Windows();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        t1.setName("窗口 1");
        t2.setName("窗口 2");
        t3.setName("窗口 3");
        t1.start();t2.start();t3.start();}
}

Lock

class A{private final ReentrantLock lock = new ReentrantLock();
    public void m(){lock.lock();
        try{// 保障线程平安的代码}
        finally{lock.unlock();
        }
    }
}

举例:三个窗口卖票

class Window implements Runnable{
    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {while(true){
            try{lock.lock();
                if(ticket > 0){
                    try {Thread.sleep(10);
                    } catch (InterruptedException e) {e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket--);
                }
            }finally {lock.unlock();
            }
        }
    }
}
public class LockTest {public static void main(String[] args) {Window w = new Window();
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.setName("线程 1");t2.setName("线程 2");t3.setName("线程 3");
        t1.start();t2.start();t3.start();}
}

synchronized 和 lock 比照:

  • lock 是显示锁,手动开启和敞开;synchronized 是隐式锁,出了作用域主动开释。
  • lock 只有代码块锁;synchronized 有代码块锁和办法锁。
  • 应用 lock 锁,JVM 将破费较少的工夫来调度线程,性能更好;并且具备更好的扩展性。

线程通信

三个办法

  • wait(): 一旦执行此办法,以后线程就进入阻塞状态,并开释同步监视器。
  • )notify(): 一旦执行此办法,就会唤醒被 wait 的一个线程。如果有多个线程被 wait,就唤醒优先级高的那个。
  • notifyAll(): 一旦执行此办法,就会唤醒所有被 wait 的线程。

阐明

  • wait(),notify(),notifyAll() 三个办法必须应用在同步代码块或同步办法中。
  • wait(),notify(),notifyAll() 三个办法的调用者必须是同步代码块或同步办法中的同步监视器。否则,会呈现 IllegalMonitorStateException 异样。
  • wait(),notify(),notifyAll() 三个办法是定义在 java.lang.Object 类中。

举例:生产者消费者问题

class Clerk{
    private int productCount = 0;
    public synchronized void produceProduct(){if(productCount < 20){
            productCount ++;
            System.out.println(Thread.currentThread().getName() + "生产第" + productCount + "个产品");
            notify();}else {
            try {wait();
            } catch (InterruptedException e) {e.printStackTrace();
            }
        }
    }

    public synchronized void consumeProduct() {if(productCount > 0){System.out.println(Thread.currentThread().getName() + "生产第" + productCount + "个产品");
            productCount --;
            notify();}else {
            try {wait();
            } catch (InterruptedException e) {e.printStackTrace();
            }
        }
    }
}
class Productor extends Thread{
    private Clerk clerk;

    public Productor(Clerk clerk) {this.clerk = clerk;}

    @Override
    public void run() {System.out.println("生产者" + Thread.currentThread().getName() + "开始生产");
        while(true){
            try {Thread.sleep(10);
            } catch (InterruptedException e) {e.printStackTrace();
            }
            clerk.produceProduct();}
    }
}
class Consumer extends Thread{
    private Clerk clerk;

    public Consumer(Clerk clerk) {this.clerk = clerk;}

    @Override
    public void run() {System.out.println("消费者" + Thread.currentThread().getName() + "取走产品");
        while(true){
            try {Thread.sleep(10);
            } catch (InterruptedException e) {e.printStackTrace();
            }
            clerk.consumeProduct();}
    }
}
public class ProductTest {public static void main(String[] args) {Clerk clerk = new Clerk();
        Productor p1 = new Productor(clerk);
        p1.setName("生产者 1");
        Consumer c1 = new Consumer(clerk);
        c1.setName("消费者 1");
        p1.start();c1.start();
    }
}

最初

在文章的最初作者为大家整顿了很多材料!包含 java 外围知识点 + 全套架构师学习材料和视频 + 一线大厂面试宝典 + 面试简历模板 + 阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题 +Spring 源码合集 +Java 架构实战电子书等等!

全副收费分享给大家,欢送关注公众号:前程有光支付!

正文完
 0