JavaLearning

多线程

多线程的创建

方式一:继承于Thread类

public class Test {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
        MyThread t2 = new MyThread();
        t2.start();
    }
}

class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
            }
        }
    }
}

方式二:实现Runnable接口

比较创建线程的两种方式

public class Test {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        Runnable target;
        Thread t1 = new Thread(m1);
        t1.setName("线程一");
        t1.start();
    }
}

class MyThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
            }
        }
    }
}

方式三:实现Callable接口。

如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?

public class Test {
    public static void main(String[] args) {
        // 1. 创建实现类的对象
        NumThread numThread = new NumThread();
        // 2. 将1中的对象传递到FutureTask构造器中
        FutureTask futureTask = new FutureTask(numThread);
        // 3. 创建Thread对象,调用start()方法
        new Thread(futureTask).start();

        // 4. 如果要获取返回值,使用下面方法
        Object obj = null;
        try {
            obj = futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("返回值为:" + obj);
    }
}

// 创建实现类
class NumThread implements Callable {
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}

方式四:使用线程池

/**
 * 线程需求一:
 */

class NumberThread implements Runnable{

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

/**
 * 线程需求二:
 */
class NumberThread1 implements Runnable{

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

public class ThreadPool {

    public static void main(String[] args) {
        //1. 提供指定线程数量的线程池
        ThreadPoolExecutor service = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);

        //设置线程池的属性
        /**
         * service.setCorePoolSize(15);
         * service.setKeepAliveTime();
         *
         * 2.执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象
         *      execute:适合适用于Runnable
         *      submit:Callable
         */

        service.execute(new NumberThread());
        service.execute(new NumberThread1());

        //3.关闭连接池
        service.shutdown();
    }

Thread中的常用方法:

线程的优先级:

如何获取和设置当前线程的优先级:

线程安全问题:同步机制

方式一:同步代码块

synchronized(同步监视器){
    //需要被同步的代码
}

说明: 1.操作共享数据的代码,即为需要被同步的代码。  -->不能包含代码多了,也不能包含代码少了。
      2.共享数据:多个线程共同操作的变量。比如:ticket就是共享数据。
      3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。

补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。

方式二:同步方法。

如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。

方法三:Lock()

synchronized 与 Lock的异同?

相同:二者都可以解决线程安全问题

不同:

2.优先使用顺序:

实践

Runnable - 代码块

class Window1 implements Runnable{ private int ticket = 100;

class Window1 implements Runnable{
    private int ticket = 100;

    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                /*同步代码块*/
                if (ticket > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

Runnable - 同步方法

class Window1 implements Runnable{
    private int ticket = 100;

    @Override
    public void run() {
        while (true){
            // 调用同步方法
            go();
        }
    }

    // 同步方法
    private synchronized void go(){
        if(ticket > 0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
            ticket--;
        }
    }
}

Thread - 同步块

class Window1 extends Thread{

    private static int ticket = 100;
    private static Object obj = new Object();

    @Override
    public void run() {
        while(true){
            synchronized (obj){
                if(ticket > 0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + ":卖票,票号为:" + ticket);
                    ticket--;
                }else{
                    break;
                }
            }
        }
    }
}

Lock

class Window1 extends Thread{

    private static int ticket = 100;
    /**
    * 实例化lock
    * */
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true){
            // 加锁
            lock.lock();
            if (ticket > 0 ) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
                ticket--;
            }else{
                break;
            }
            // 解锁
            lock.unlock();
        }
    }
}

线程通信

线程通信的例子:使用两个线程打印 1-100。线程1, 线程2 交替打印

涉及到的三个方法

说明

sleep() 和 wait()的异同?