栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java多线程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java多线程

java多线程 程序、进程、线程:
  • 程序:一段静态代码。
  • 进程:正在执行的程序。一个进程可以有多个线程。进程是操作系统资源分配的基本单位。
  • 线程:程序内部的一条执行路径。线程是处理器任务调度和执行的基本单位。
并行与并发:
  • 并行:多CPU同时执行多个任务
  • 并发:一个CPU”同时“执行多个任务
多线程优点:
  • 提高CPU利用率;
  • 提高应用程序的响应,增强用户体验;
  • 改善程序结构。
Thread常用方法:
  • start():启动当前线程,调用run()方法
  • run():通常需要重写,将创建的线程要执行的操作声明在此方法中
  • currentThread():返回当前代码的线程
  • getName():获取当前线程名
  • setName():设置当前线程名
  • yield():释放当前线程CPU控制权
  • join():线程a调用线程b的join(),此时线程a进入阻塞状态,直至线程b完全执行完毕,线程a阻塞状态才结束。
  • sleep(long millitime):是当前线程睡眠指定时间
  • isAlive():判断当前线程是否存活
线程的创建和使用:

方法一:继承Thread类

  • 创建一个继承于Thread类的子类
  • 重写run()方法,将此线程操作声明在run()中;
  • 创建子类对象
  • 通过此对象调用start()
class MyThread extends Thread{
    @Override
    public void run() {
        for (int i=0;i<20;i++){
            if (i%2==0){
                System.out.println(i);
            }
        }
    }
}

public class test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        //start()作用:启动当前线程;调用当前线程的run();
        myThread.start();
        for (int i=0;i<20;i++){
            if (i%2==0){
                System.out.println("**** "+i+" ****");
            }
        }
    }

}

方法二:实现Runnable接口

  • 创建一个实现Runnable接口的类
  • 实现类实现Runnable接口的抽象方法:run()
  • 创建实现类的对象
  • 将此对象作为参数传递到Thread类的构造器中,创建Thread类对象
  • 通过Thread类的对象调用start()
class MyThread implements Runnable{
    @Override
    public void run() {
        for (int i=0;i<20;i++){
            if (i%2==0){
                System.out.println(Thread.currentThread().getName()+i);
            }
        }
    }
}

public class test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
        for (int i=0;i<20;i++){
            if (i%2==0){
                System.out.println(Thread.currentThread().getName()+"**** "+i+" ****");
            }
        }
    }

}

方法三:实现Callable接口

与Runnable相比,Callable功能更加强大

  • run()方法可以有返回值
  • 方法可以抛出异常
  • 支持泛型的返回值
  • 需要借助FutureTask类,如获取返回结果
//1.创建一个实现Callable的实现类
class MyThread implements Callable{
    //2.实现call方法,将此线程执行的操作声明在此;
    @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;
    }
}
public class test {
    public static void main(String[] args) {
        //3.创建实现类对象
        MyThread myThread = new MyThread();
        //4.将此对象传递到FutureTask中
        FutureTask futureTask = new FutureTask(myThread);
        //5.将FutureTask的对象传递到Thread中
        Thread thread = new Thread(futureTask);
        thread.start();
        //6.获取call方法返回值
        try {
            Object o = futureTask.get();
            System.out.println("总和为"+o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

方法四:使用线程池

提前创建多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。

好处:

  • 提高响应速度(减少创建新线程的时间)
  • 降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
  • 便于线程管理
class MyThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0;i<20;i++){
            System.out.println(i);
        }
    }
}
public class test {
    public static void main(String[] args) {
        //1提供指定数量的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //2执行线程操作
        executorService.execute(new MyThread());
        //Callable
        //executorService.submit(Callable callable);
        //3关闭线程池
        executorService.shutdown();

    }

}
线程优先级: 线程优先等级:
  • MAX_PRIORITY:10
  • MIN_PRIORITY:1
  • NORM_PRIORITY:5
获取和设置当前线程优先级:
  • getPriority():获取当前线程优先级
  • setPriority(int p):设置线程的优先级
同步机制解决线程安全问题:

优点:解决了线程安全问题

缺点:效率低。操作同步代码时,只能有一个线程参与,其他线程等待。

方法一:同步代码块

synchronized(同步监视器){

​ //需要被同步的代码

}

  • 操作共享数据的代码,即需要被同步的代码
  • 共享数据:多个线程共同操作的变量
  • 同步监视器,俗称锁。任何一个类的对象都可以充当锁。多个线程必须要共用同一把锁。

①使用同步代码块解决实现Runnable接口的线程安全问题

class MyThread implements Runnable{
    private int num = 60;
    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                if (num > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num--;
                } else {
                    break;
                }
            }
        }
    }
}

public class test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        Thread thread3 = new Thread(myThread);
        thread1.setName("1号");
        thread2.setName("2号");
        thread3.setName("3号");
        thread1.start();
        thread2.start();
        thread3.start();
    }

}

②使用同步代码块解决继承Thread类的线程安全问题

class MyThread extends Thread{
    private static int num = 60;
    @Override
    public void run() {
        while (true) {
            synchronized (MyThread.class) {
                if (num > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num--;
                } else {
                    break;
                }
            }
        }
    }
}

public class test {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();
        MyThread thread3 = new MyThread();
        thread1.setName("1号");
        thread2.setName("2号");
        thread3.setName("3号");
        thread1.start();
        thread2.start();
        thread3.start();
    }

}

方法二:同步方法

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

  • 同步方法任然涉及同步监视器,只是不需要显式声明
  • 非静态的同步方法,同步监视器是this
  • 静态的同步方法,同步监视器是当前类本身

①使用同步方法解决实现Runnable接口的线程安全问题

class MyThread implements Runnable{
    private int num = 60;
    @Override
    public void run() {
        while (true) {
            show();
            if (num ==0){
                break;
            }
        }
    }
    private synchronized void show(){
        if (num > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + num);
            num--;
        }
    }
}

public class test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        Thread thread3 = new Thread(myThread);
        thread1.setName("1号");
        thread2.setName("2号");
        thread3.setName("3号");
        thread1.start();
        thread2.start();
        thread3.start();
    }

}

②使用同步方法解决继承Thread类的线程安全问题

class MyThread extends Thread{
    private static int num = 60;
    @Override
    public void run() {
        while (true) {
            show();
            if (num ==0){
                break;
            }
        }
    }
    private static synchronized void show(){
        if (num > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + num);
            num--;
        }
    }
}

public class test {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();
        MyThread thread3 = new MyThread();
        thread1.setName("1号");
        thread2.setName("2号");
        thread3.setName("3号");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

方法三:Lock

ReentrantLock类实现了Lock,拥有与synchronized相同的并发性和内存语义。

class MyThread implements Runnable{
    private int num = 60;
    //1.实例化ReentrantLock
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            try {
            //2.调用锁定方法lock()
                lock.lock();
                if (num > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num--;
                }else {
                    break;
                }
            } finally {
            //3.调用解锁方法:unlock()
                lock.unlock();
            }
        }
    }
}

public class test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        Thread thread3 = new Thread(myThread);
        thread1.setName("1号");
        thread2.setName("2号");
        thread3.setName("3号");
        thread1.start();
        thread2.start();
        thread3.start();
    }

}
synchronized与Lock的异同:

相同点:

  • 二者都可以解决线程安全问题

不同点:

  • synchronized机制在执行完相应的同步代码后,自动释放同步监视器;Lock需要手动启动同步(lock()),手动结束(unlock())
  • Lock只有代码块锁,synchronized有代码锁和方法锁
  • 使用Lock锁,JVM将花费更少的时间来调度线程,性能更好,并且具有更好的扩展性。
使用同步机制将单例模式中的懒汉式改写为线程安全的
public class SingletonTest {
    public static void main(String[] args) {
        User user1 = User.getUser();
        User user2 = User.getUser();
        System.out.println(user1 == user2);

    }
    static synchronized class User{
        //1.私有化构造器
        private User(){

        }
        //2.内部创建类的对象
        //4.要求此对象的声明也必须是静态的
        private static User user = null;
        //3.提供公共的方法,返回类的对象
        public static User getUser(){
            if (user == null){
                user = new User();
            }
            return user;
        }
    }
}

死锁问题

不同线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了死锁。

出现死锁后,既不会出现异常,也不会出现提示,只是所有线程都处于阻塞状态,无法继续。

解决方法:

  • 尽量减少同步资源的定义
  • 尽量避免嵌套同步
public class test {
    public static void main(String[] args) {
        StringBuffer s1 = new StringBuffer();
        StringBuffer s2 = new StringBuffer();
        new Thread(){
            @Override
            public void run() {
                synchronized(s1){
                    s1.append("a");
                    s2.append("1");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized(s2){
                        s1.append("b");
                        s2.append("2");
                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }.start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(s2){
                    s2.append("d");
                    s1.append("3");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized(s1){
                        s2.append("c");
                        s2.append("4");
                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }).start();
    }
}
线程通信
  • wait():当前线程进入阻塞状态,并释放同步监视器
  • notify():唤醒被wait的一个线程,如果有多个线程被wait,就唤醒优先级高的。
  • notifyAll():唤醒所有被wait的线程

wait(),notify(),notifyAll()必须使用在同步代码块或同步方法中

class MyThread implements Runnable{
    private int num = 30;

    @Override
    public void run() {
        while (true) {
            synchronized(this) {
                notify();
                if (num > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num--;
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }

}

public class test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        thread1.setName("1号");
        thread2.setName("2号");

        thread1.start();
        thread2.start();

    }

}
sleep()和wait()的异同

相同点:

  • 都可以使当前线程进入阻塞状态

不同点:

  • 声明位置不同。Thread类中声明sleep(),Object类中声明wait()
  • 调用要求不同。sleep()可以在任何需要的场景下调用。wait()必须使用在同步代码块或同步方法中。
  • 如果两个都使用在同步代码块或同步方法中。sleep()不释放同步监视器,wait()释放同步监视器。
生产者和消费者问题

生产者将产品交给店员,而消费者从店员处取走产品。店员只能持有一定数量的产品,到达一定数量,叫停生产者,店中有空位,再通知生产者继续生产;如果店中没有产品了,就让消费者等待,有产品再通知消费者。

class Clerk{
    private int productCount = 0;

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

    public synchronized void produceProduct() {
        if (productCount < 20){
            productCount++;
            notify();
            System.out.println(Thread.currentThread().getName()+"生产第"+productCount+"个产品");
        } else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Producer extends Thread{
    private Clerk clerk;
    public Producer(Clerk clerk){
        this.clerk = clerk;
    }
    @Override
    public void run() {
        System.out.println(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(getName()+"开始消费产品....");
        while (true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.consumeProduct();
        }
    }
}
public class test {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Producer producer = new Producer(clerk);
        Consumer consumer = new Consumer(clerk);
        producer.setName("生产者");
        consumer.setName("消费者");
        producer.start();
        consumer.start();
    }

}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1004160.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号