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

Java高级语法(一):多线程

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

Java高级语法(一):多线程

1.基本概念:程序、进程、线程

2.线程的创建和使用

        1.多线程的创建:

                1.方式一:继承于Thread类

                        1.创建一个继承于Thread类的子类

                        2.重写Thread类的run() → 将此线程执行的操作声明在run()中

                        3.创建Thread类的子类的对象

                        4.通过此对象调用start() → ①启动当前线程 ②调用当前线程的run()

                        5.创建过程中的两个问题说明:

                                1.我们不能通过直接调用run()的方式启动线程。

                                2.再启动一个线程,不可以还让已经start()的线程去执行。会报异常(IllegalThreadStateException)我们需要重新创建一个线程的对象

                2.方式二:实现Runnable接口

                        1.创建一个实现了Runnable接口的类

                        2.实现类去实现Runnable中的抽象方法:run()

                        3.创建实现类的对象

                        4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

                        5.通过Thread类的对象调用start() → 调用了Runnabl类型的target 的run()

                比较创建线程的两种方式:

                开发中:优先选择:实现Runnable接口的方式

                        1.实现的方式没有类的单继承性的局限性

                        2.实现的方式更适合来处理多个线程有共享数据的情况。

                        3.联系:Thread类实现了Runnable接口(两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。)

        2.Thread类的有关方法

        3 .线程的优先级

                1.优先级等级

                        1.MAX_PRIORITY:10

                        2.MIN_PRIORITY:1

                        3.NORMPRIORITY:5(默认)

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

                        1.getPriority()∶获取线程的优先级

                        2.setpriority(int p)∶设置线程的优先级

                   说明:高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。 3.线程的生命周期

 

4.线程的同步(解决线程安全问题)

        1.同步代码块

                 说明:

                        1.操作共享数据的代码,即为需要被同步的代码 → (不能包含代码多了,也不能包含代码少了)

                        2.共享数据:多个线程共同操作的变量。比如: ticket就是共享数据。

                        3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。

                           要求:多个线程必须要共用同一把锁。

                           补充:

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

                                2.在继承Thread类创建多线程的方式中,慎用this充当同步监视器,考虑使用当前类充当同步监视器。

        2.同步方法

                如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。(即在方法返回值前添加synchronized)

                1.同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。

                2.非静态的同步方法,同步监视器是:this

                   静态的同步方法,同步监视器是:当前类本身

        同步的方式,解决了线程的安全问题。 → 好处

        操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程
效率低。 → 局限性

        3.Lock锁(JDK5.0新增)

                1.实例化ReentrantLock

                2.调用锁定方法lock()

                3.调用解锁方法unlock()

 

        4.线程的死锁问题 

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

                2.说明:

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

                        2.我们使用同步时,要避免出现死锁

5.线程的通信

        三个方法:wait()、notify()、notifyAll()

        1.wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。

        2.notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个

        3.notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。

        4.说明:

                1.wait()、notify()、notifyAll()三个方法必须使用在同步代码块或同步方法中。

                2.wait()、notify()、notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则,会出现IllegalThreadStateException异常

                3.wait()、notify()、notifyAll()三个方法是定义在java.lang.Object类中。

6.JDK5.0新增的线程创建方式

        1.实现Callable接口

                1.创建一个实现Callable的实现类

                2.实现call()方法,将此线程需要执行的操作声明在call()中

                3.创建Callable接口实现类的对象

                4.将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象

                5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()

                6.获取Callable中call方法的返回值(如不需要可以不写)

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

                        1.call()可以有返回值的。

                        2.call()可以抛出异常,被外面的方法捕获,获取异常信息

                        3.Callabl是支持泛型的

        2.使用线程池

                1.提供指定线程数量的线程池

                2.执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象

                3.关闭连接池

练习1(线程:继承于Thread类)
package com.wy.java.exer;


public class ThreadDemo {
    public static void main(String[] args) {
        MyThread1 m1 = new MyThread1();
        MyThread2 m2 = new MyThread2();

        m1.start();
        m2.start();
    }
}

class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
class MyThread2 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
练习2(线程:实现Runnable接口)
package com.wy.java;



class Window1 implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            if (ticket > 0){
                System.out.println(Thread.currentThread().getName() + ": 买票,票号为: " + ticket);
                ticket--;
            }else {
                break;
            }
        }
    }
}

public class WindowTes1 {
    public static void main(String[] args) {
        Window1 w1 = new Window1();

        Thread t1 = new Thread(w1);
        Thread t2 = new Thread(w1);
        Thread t3 = new Thread(w1);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }



}
练习3(线程同步:同步代码块)
package com.wy.java;



class Window1 implements Runnable {
    private int ticket = 100;
//    Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (this) {//此时this: 唯一的对象 //synchronized (obj) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ": 卖票,票号为: " + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }

    }
}

public class WindowTest1 {
    public static void main(String[] args) {
        Window1 w1 = new Window1();

        Thread t1 = new Thread(w1);
        Thread t2 = new Thread(w1);
        Thread t3 = new Thread(w1);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }


}
练习4(线程同步:同步方法)
package com.wy.java;


class Window4 extends Thread {
    private static int titck = 100;

    @Override
    public void run() {
        while (true) {
             show();
        }
    }
    private static synchronized void show(){//同步监视器是: Window4.class
//    private synchronized void show(){//同步监视器是: t1,t2,t3,此种解决方法是错误的
        if (titck > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ": 卖票,票号为: " + titck);
            titck--;
        }
    }
}

public class WindowTest4 {
    public static void main(String[] args) {
        Window4 w1 = new Window4();
        Window4 w2 = new Window4();
        Window4 w3 = new Window4();

        w1.setName("窗口1");
        w2.setName("窗口2");
        w3.setName("窗口3");

        w1.start();
        w2.start();
        w3.start();
    }
}
练习5(线程同步:Lock锁) 
package com.wy.java1;

import java.util.concurrent.locks.ReentrantLock;



class Window implements Runnable {
    private int ticket = 100;

    //1.实例化ReentrantLock
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                //2.调用锁定方法lock()
                lock.lock();

                if (ticket > 0) {

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + "售票,票号为: " + ticket);
                    ticket--;
                } else {
                    break;
                }
            } finally {
                //3.调用解锁方法unlock()
                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();
    }
}
练习6(单例模式:懒汉式-线程安全)
package com.wy.java1;


public class BankTest {

}

class Bank {
    private Bank() {
    }

    private static Bank instance = null;

    public static Bank getInstance() {

        //方式一: 效率稍差
//        synchronized (Bank.class) {
//            if (instance == null) {
//                instance = new Bank();
//            }
//            return instance;
//        }

        //方式二: 效率更高
        if (instance == null) {
            synchronized (Bank.class) {
                if (instance == null) {
                    instance = new Bank();
                }
            }
        }
        return instance;
    }
}
练习7(死锁)
package com.wy.java1;


public class ThreadTest {
    public static void main(String[] args) {
        StringBuffer s1 = new StringBuffer();
        StringBuffer s2 = new StringBuffer();

        new Thread(){
            @Override
            public void run() {
                synchronized (s1){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    s1.append("a");
                    s2.append("1");
                    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){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    s1.append("c");
                    s2.append("3");
                    synchronized (s1){
                        s1.append("d");
                        s2.append("4");

                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }).start();
    }
}
练习8(线程同步练习)
package com.wy.exer1;



class Account{
    private double balance;

    public Account(double balance) {
        this.balance = balance;
    }

    //存钱
    public synchronized void addmoney(double amt){
        if (amt > 0){
            balance += amt;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":"  + "存钱成功,余额为: " + balance);
        }
    }
}

class Customer extends Thread{
    private Account account;

    public Customer(Account account) {
        this.account = account;
    }

    @Override
    public void run() {

        for (int i = 0; i < 3; i++) {
            account.addmoney(1000);
        }
    }
}

public class AccountTest {
    public static void main(String[] args) {
        Account account = new Account(0);
        Customer c1 = new Customer(account);
        Customer c2 = new Customer(account);

        c1.setName("甲");
        c2.setName("乙");

        c1.start();
        c2.start();

    }
}
练习9(线程通信)
package com.wy.java1;


class Number implements Runnable {
    private int number = 1;

    @Override
    public void run() {
        while (true) {
            synchronized (this) {

                //唤醒另一个线程
                notify();

                if (number <= 100) {

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + ":" + number);
                    number++;

                    try {
                        //使得调用如下wait()方法的线程进入阻塞状态
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                } else {
                    break;
                }
            }
        }
    }
}


public class CommunicationTest {
    public static void main(String[] args) {
        Number number = new Number();

        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);

        t1.setName("线程1");
        t2.setName("线程2");

        t1.start();
        t2.start();
    }
}
练习10(线程通信:生产者消费者问题)
package com.wy.java1;


class Clerk {

    private int productCount = 0;

    //生产产品
    public synchronized void produceRroduct() {
        if (productCount < 20){
            productCount++;
            System.out.println(Thread.currentThread().getName() + ": 开始生产第" + productCount + "个产品");

            notify();

        }else {
            //等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //消费产品
    public synchronized void consumeRroduct() {
        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 = new Clerk();

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

    @Override
    public void run() {
        System.out.println(getName() + ": 开始生产产品..." );

        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        while (true){
            clerk.produceRroduct();
        }
    }
}

class Customer extends Thread{//消费者
    private Clerk clerk = new Clerk();

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

    @Override
    public void run() {
        System.out.println(getName() + ": 开始消费产品..." );

        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        while (true){
            clerk.consumeRroduct();
        }
    }
}

public class ProductTest {
    public static void main(String[] args) {
        Clerk clerk  = new Clerk();

        Productor p1 = new Productor(clerk);
        p1.setName("生产者1");

        Customer c1 = new Customer(clerk);
        c1.setName("消费者1");
        Customer c2 = new Customer(clerk);
        c2.setName("消费者2");

        p1.start();
        c1.start();
        c2.start();
    }


}
练习11(线程:实现Callable接口)
package com.wy.java1;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;


//1.创建一个实现Callable的实现类
class NumThread implements Callable{
    //2.实现call()方法,将此线程需要执行的操作声明在call()中
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}
public class ThreadNew {
    public static void main(String[] args) {
        //3.创建Callable接口实现类的对象
        NumThread numThread = new NumThread();

        //4.将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
        FutureTask futureTask = new FutureTask(numThread);

        //5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
        new Thread(futureTask).start();
        try {
            //6.获取Callable中call方法的返回值
            //get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值
            Object sum = futureTask.get();
            System.out.println("总和为:" + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
练习12(线程:线程池)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/584076.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

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

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