Java高级编程之多线程

1.程序、进程、线程:

  • 程序:是指为实现一定功能的由计算机语言编写的一组指令的集合,可理解为静态的代码;
  • 进程:可以理解为一个正在执行的程序或程序的一次执行过程,它具有生命周期;进程作为资源分配的单位,运行在系统时会为每个进程分配不同的内存区域;
  • 线程:线程可以理解为进程的进一步细分,一个进程可以有多个线程;(一个 java.exe至少有三个线程:main方法主线程、GC垃圾回收线程、异常处理线程)

2.创建线程

  • 方式①
    继承Thread类重写run方法:
class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                //让当前线程休眠10毫秒
                Thread.sleep(10);
            } catch (InterruptedException e) {
                    e.printStackTrace();
            }
            System.out.println(i+"====="+Thread.currentThread().getName());
        }
    }
}

public class ThreadTest {
    public static void main(String[] args){
    	//主方法线程循环打印0-499
    	for (int i = 0; i < 500; i++)   System.out.println(i+"====="+Thread.currentThread().getName()); 
    	//创建自定义线程对象
	MyThread thread = new MyThread();
	//重新命名自定义线程
	thread.setName("MyThread");
	//设置线程优先级
	thread.setPriority(Thread.MAX_PRIORITY);
	//启动自定义线程
	thread.start();
}
  • 方式②
    实现Runnable接口重写run方法:
class  MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++)	System.out.println(i+"====="+Thread.currentThread().getName())
    }
}

public class ThreadTest {
    public static void main(String[] args){  
        for (int i = 0; i < 500; i++)   System.out.println(i+"====="+Thread.currentThread().getName()); 
        
        Thread thread1=new Thread(new MyRunnable(),"MyRunnable");
        thread1.setPriority(Thread.MAX_PRIORITY);
        thread1.start();
    }
}
  • 方式③
    实现Callable接口重写call方法:
class MyCallable implements Callable{
 
    @Override
    public Integer call() throws Exception { //返回类型为Integer
        Thread.sleep(100);
        int sum = 0;
        for(int i=0;i<100;i++)	sum += i;
        return sum;
    }
}

public class FutureTest {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool(); //构造线程池
        MyCallable task = new MyCallable();
        Future result = executor.submit(task); //获取任务执行结果
        executor.shutdown();     
        try {
            System.out.println("task运行结果"+result.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • tips:
    ①线程在启动【start()】之后会执行继承了Thread的类中的run方法中的代码
    ②实现了Runnable接口意味着该类具有可执行性,但该实现类不是线程类
    ③多个线程同时执行,它们之间是互不干扰的,并且线程的执行具有随机性
    ④线程有十个优先级(1-10)但设置的线程优先级高的不一定会被CPU优先执行
    ⑤继承Thread类和实现Runnable接口两种方式的比较:
    • Thread类实现了Runnable接口(联系)
    • Runnable接口解决了单继承的局限性
    • 当有共享数据时,使用实现方式更好,同时共享数据所在的类可以作为Runnable接口的实现类

3.线程的状态:

  • 创建:new Thread()//创建线程对象,并给线程设置默认名称
  • 就绪:当线程对象调用start()方法时,线程进入就绪状态,该线程状态表示可被执行,并不一定立即被执行;
  • 运行:当CPU调度到某线程时,该线程处于运行状态
  • 阻塞:sleep()、wait()、join()、suspend()【过时】、线程同步锁【当线程进入阻塞状态时,会暂时让出CPU资源】
  • 死亡:正常执行完run()/main()方法、线程对象调用stop()、Error/Exception未被处理;
  • 线程状态图:
    Java高级编程之多线程_第1张图片

4.线程的同步机制

  • 前提:如果我们创建的多线程中有存在着共享数据,那么就有可能出现出现线程安全问题:当其中一个线程操作共享数据还未结束时,另一个线程参与进来,导致共享数据的操作出现问题。
  • 解决方法:要求一个线程完成对共享资源的操作之后,其他的线程才能操作共享资源
    • 方式一:同步代码块:
      synchronized( 同步监视器 ){ //操作共享数据的代码 }

      • 注:
        同步监视器:俗称,任何一个类的对象都可以才充当锁。要想保证线程的安全,必须要 求所有的线程共用同一把锁
        ②使用实现Runnable接口的方式创建多线程的话,同步代码块中的锁,可以考虑是【this】。如 果使用继承Thread类的方式,不用this,可以考虑【类名.class
        共享数据:多个线程需要共同操作的变量。 明确哪部分是操作共享数据的代码。
    • 方式二:同步方法
      将操作共享数据的方法声明为synchronized
      比如:public synchronized void show(){ //操作共享数据的代码}
      注:①.对于非静态的方法而言,使用同步的话,默认锁为:this。如果使用在继承的方式实现多线程 的话,慎用this!
      ②静态的方法如果使用同步,默认的锁为:当前类本身。

    • tips:

      • 释放锁:wait()
      • 不释放锁:sleep()、yield()
      • 死锁:不同的线程分别占用对方的同步资源不放弃,都在等对方放弃自己需要的同步资源,这就形 成了死锁(死锁无法解决,只能避免)例:
public class DeadLock {  
    private static String Stephen="Stephen";  
    private static String Curry="Curry";  
    public static void main(String[] args){  
        new DeadLock().deadLock();  
    }   
  private void deadLock(){  
        Thread threadA=new Thread(new Runnable(){  
            @Override  
            public void run(){  
                synchronized(Stephen){  
                    try {  
                        Thread.currentThread().sleep(1000);
                    } catch (InterruptedException e) {   
                        e.printStackTrace();  
                    }  
                    synchronized(Curry){  
                        System.out.println("AB");  
                    }  
                }  
            }  
        }).start(); 
       Thread threadB=new Thread(new Runnable(){  
            @Override  
            public void run(){  
                synchronized(Curry){  
                    try {  
                        Thread.currentThread().sleep(1000);  
                    } catch (InterruptedException e) {   
                        e.printStackTrace();  
                    }  
                    synchronized(Stephen){  
                        System.out.println("BA");  
                    }  
                }  
            }  
        }).start();
    }  
} 

5.线程的通信
①两个线程交替打印1-100自然数

public class CommunicationTest {

    public static void main(String[] args) {
        Print print = new Print();
        Thread thread1 = new Thread(print);
        Thread thread2 = new Thread(print);

        thread1.setName("线程1打印:");
        thread1.start();

        thread2.setName("线程2打印:");
        thread2.start();
    }
}

class Print implements Runnable {
    public static int num = 1;

    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                if (num <= 100) {
                    //唤醒另外一个线程
                    this.notify();            
                    System.out.println(Thread.currentThread().getName()+(num++));

                    try {                       
                        wait(); //该线程释放资源进去阻塞状态
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else  break;
            }
        }
    }
}

②生产者与消费者

public class TestProductAndCustomer {
    public static void main(String[] args) {
        Waitter waitter = new Waitter();
        Productor p = new Productor(waitter);
        Customer c1 = new Customer(waitter);
        Customer c2 = new Customer(waitter);

        new Thread(p).start();
        new Thread(c1).start();
        new Thread(c2).start();

    }
}

class Waitter {
    private int produce = 0;

    public synchronized void produce() {
        if (produce < 20) {
            produce++;
            System.out.println(Thread.currentThread().getName() +
                    "生产了第" + produce + "个产品");
            notify();
        } else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }
    public synchronized void custom() {

        if (produce > 0) {
            System.out.println(Thread.currentThread().getName() +
                    "消费了第" + produce + "个产品");
            produce--;
            notify();
        } else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Productor implements Runnable {
    private Waitter waitter;

    public Productor(Waitter waitter) {
        this.waitter = waitter;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            waitter.produce();
        }
    }
}

class Customer implements Runnable {
    private Waitter waitter;

    public Customer(Waitter waitter) {
        this.waitter = waitter;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            waitter.custom();
        }
    }
}

tips:
线程的通信:如下的三个方法必须使用在同步代码块或同步方法中:

  • wait():当在同步中,执行到此方法,则此线程“等待”,直至其他线程执行notify()的方法,将其唤醒,唤醒后继续其wait()后的代码

  • notify()/notifyAll():在同步中,执行到此方法,则唤醒其他的某一个或所有的被wait的线程。

  • 线程安全的懒汉式:

class SingleTon{
    private static SingleTon instance;
    private SingleTon() {}
    public static SingleTon1 getIntance(){
        if (instance==null){
            synchronized (SingleTon1.class){
                if(instance==null)
                    return instance=new SingleTon1();
            }
        }
        return instance;
    }
}

你可能感兴趣的:(大数据之Javase,大数据之java基础总结)