Java高级特性:多线程

导读:本篇文章讲解 Java高级特性:多线程,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

多线程

主线程

线程的创建和启动

1、继承Thread类创建线程

2、实现Runnable接口创建线程

线程状态

1、线程优先级

2、线程休眠

3、线程的强制运行

4、线程的礼让

多线程共享数据引发的问题

Hashtable 与 HashMap的区别


多线程

什么是多线程:如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程”多个线程交替占用CPU资源,而非真正的并行执行

多线程好处:1、充分利用CPU的资源,2、简化编程模型,3、带来良好的用户体验

Thread类:Java提供了java.lang.Thread类支持多线程编程

主线程

main()方法即为主线程入口

产生其他子线程的线程

必须最后完成执行,因为它执行各种关闭动作

public static void main(String args[]) {
		Thread t= Thread.currentThread(); 
		System.out.println("当前线程是: "+t.getName()); 
		t.setName("MyJavaThread"); 
		System.out.println("当前线程名是: "+t.getName()); 
}

线程的创建和启动

在Java中创建线程的两种方式

继承java.lang.Thread类

实现java.lang.Runnable接口

使用线程的步骤:1、定义线程2、创建线程对象3、启动线程4、终止线程

1、继承Thread类创建线程

定义MyThread类继承Thread

重写run()方法,编写线程执行体

创建线程对象,调用start()方法启动线程

实例:

public class MyThread extends Thread{
    //重写run()方法
	public void run(){
		for(int i=1;i<100;i++){			System.out.println(
        Thread.currentThread().getName()+":"+i);
        }
    }
}
public static void main(String[] args) {
		MyThread thread = new MyThread();
		thread.start(); //启动线程
}

 多个线程交替执行,不是真正的“并行” 线程每次执行时长由分配的CPU时间片长度决定

MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start();
t2.start(); 

启动线程不可以直接调用run()方法,要使用start()方法

2、实现Runnable接口创建线程

定义MyRunnable类实现Runnable接口

实现run()方法,编写线程执行体

创建线程对象,调用start()方法启动线程

public class MyRunnable implements Runnable{
	public void run(){
		for(int i=1;i<100;i++){			System.out.println(
        Thread.currentThread().getName()+":"+i);
        }
    }
}
public static void main(String[] args) {
		MyRunnable myRunnable = new MyRunnable();
		Thread myThread = new Thread(myRunnable);	
		thread.start(); //启动线程
}

继承Thread类: 1、编写简单,可直接操作线程;2、适用于单继承

实现Runnable接口:1、避免单继承局限性;2、便于共享资源

线程状态

1、创建状态;2、就绪状态;3、运行状态;4、阻塞状态;5、死亡状态

Java高级特性:多线程

 线程调度:线程调度指按照特定机制为多个线程分配CPU的使用权

方法 说明

void setPriority(int  newPriority)

更改线程的优先级

static void sleep(long millis)

在指定的毫秒数内让当前正在执行的线程休眠

void join()

等待该线程终止

static void yield()

暂停当前正在执行的线程对象,并执行其他线程

void interrupt()

中断线程

boolean isAlive()

测试线程是否处于活动状态

1、线程优先级

线程优先级由1~10表示,1最低,默认优先级为5

优先级高的线程获得CPU资源的概率较大

实例:

public class Runable implements Runnable{
    //重写run方法
    @Override
    public void run() {
        for (int i = 1; i < 10; i++) {
            Thread thread = Thread.currentThread();
            System.out.println("你好:来自线程:" + thread.getName());
        }
    }
    public static void main(String[] args) {
        Runable runable = new Runable();
        Thread thread1 = new Thread(runable);
        Thread thread2 = new Thread(runable);
        //修改线程名字
        thread1.setName("A");
        thread2.setName("B");
        //设置线程优先级
        thread1.setPriority(8);
        thread2.setPriority(4);
        //启动线程
        thread1.start();
        thread2.start();
    }
}

2、线程休眠

让线程暂时睡眠指定时长,线程进入阻塞状态,睡眠时间过后线程会再进入可运行状态

实例:

public class Runable implements Runnable{
    //重写run方法
    @Override
    public void run() {
        for (int i = 1; i < 10; i++) {
            try {
                //线程休眠,并处理异常
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Thread thread = Thread.currentThread();
            System.out.println("你好:来自线程:" + thread.getName());
        }
    }
    public static void main(String[] args) {
        Runable runable = new Runable();
        Thread thread1 = new Thread(runable);
        Thread thread2 = new Thread(runable);
        //修改线程名字
        thread1.setName("A");
        thread2.setName("B");
        //设置线程优先级
        thread1.setPriority(8);
        thread2.setPriority(4);
        //启动线程
        thread1.start();
        thread2.start();
    }
}

3、线程的强制运行

使当前线程暂停执行,等待其他线程结束后再继续执行本线程

方法:

1、public final void join()

2、public final void join(long mills)

3、public final void join(long mills,int nanos)

millis:以毫秒为单位的等待时长,nanos:要等待的附加纳秒时长,需处理InterruptedException异常

实例:

重写run方法

public class MyRunnable implements Runnable{
    private String name;

    private String gender;

    public MyRunnable(String name, String gender) {
        this.name = name;
        this.gender = gender;
    }

    public MyRunnable() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public void run() {
        for(int i = 0; i < 5; i++){
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t" + i);
        }
    }
}

实现线程阻塞:

public class JoinThreadTest {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable("张三","男");
        Thread myThread = new Thread(myRunnable);

        myThread.start();

        for (int i=0;i<20;i++){
            if(i==5){
                try {
                    //线程阻塞
                    myThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"运行:"+i);
        }
    }
}

4、线程的礼让

暂停当前线程,允许其他具有相同优先级的线程获得运行机会

该线程处于就绪状态,不转为阻塞状态

方法:

public static void yield()

 只是提供一种可能,但是不能保证一定会实现礼让

实例:

重写run方法

public class YieldRunnable implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<15;i++){
            String name = Thread.currentThread().getName();
            System.out.println(name+"正在运行:"+i);
            /*if(i==3){
                System.out.print(name + "线程礼让:");
                Thread.yield();
            }*/
            System.out.print(name + "线程礼让:");
            Thread.yield();
        }
    }
}

实现线程礼让:

public class YieldThreadTest {
    public static void main(String[] args) {
        YieldRunnable runnable = new YieldRunnable();

        Thread t1 = new Thread(runnable);
        t1.setName("线程A");
        Thread t2 = new Thread(runnable);
        t2.setName("线程B");

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

}

多线程共享数据引发的问题

多个线程操作同一共享资源时,将引发数据不安全问题

 使用同步方法同步代码块可以解决这些问题

使用synchronized修饰的方法控制对类成员变量的访问

同步方法语法:

访问修饰符 synchronized 返回类型 方法名(参数列表){……}
或者
synchronized 访问修饰符 返回类型 方法名(参数列表){……}

同步方法实例:

同步方法多个线程抢火车票

public class TrainRunnable implements Runnable{
    private int num;

    private int count = 10;

    private boolean flag = false;

    @Override
    public void run() {
        while (!flag) {
            //省略代码:判断是否余票
            sale();
        }
        System.out.println("票已抢完!");
    }

    private synchronized void sale(){
        if (count <= 0) {
            flag = true;
            return;
        }

        try {
            Thread.sleep(500); //模拟网络延时
        } catch (InterruptedException e) {//…}
            e.printStackTrace();
        }
        count--;
        num++;
        System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票!");
    }

    public static void main(String[] args) {
        TrainRunnable trainTest1 = new TrainRunnable();
        Thread a = new Thread(trainTest1);
        Thread b = new Thread(trainTest1);
        Thread c = new Thread(trainTest1);
        a.setName("客户:A");
        b.setName("客户:B");
        c.setName("客户:C");


        a.start();
        b.start();
        c.start();
    }
}

同步代码块

使用synchronized关键字修饰的代码块

同步代码块语法:

synchronized(syncObject){
    //需要同步的代码
}

 syncObject为需同步的对象,通常为this,效果与同步方法相同

同步代码块多个线程抢火车票:

public class TrainThread implements Runnable{
    private int num;

    private int count = 10;

    @Override
    public void run() {
        while (true) {
            //省略代码:判断是否余票
            synchronized (this){
                if (count <= 0) {
                    System.out.println("票已抢完!");
                    break;
                }

                try {
                    Thread.sleep(500); //模拟网络延时
                } catch (InterruptedException e) {//…}
                    e.printStackTrace();
                }
                count--;
                num++;
                System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票!");
            }

        }
    }

    public static void main(String[] args) {
        TrainThread trainTest1 = new TrainThread();
        Thread a = new Thread(trainTest1);
        Thread b = new Thread(trainTest1);
        Thread c = new Thread(trainTest1);
        a.setPriority(Thread.MAX_PRIORITY);
        a.setName("客户:A");
        b.setName("客户:B");
        c.setName("客户:C");

        a.start();
        b.start();
        c.start();
    }
}

 多个并发线程访问同一资源的同步代码块时

同一时刻只能有一个线程进入synchronizedthis)同步代码块

当一个线程访问一个synchronizedthis)同步代码块时,其他synchronizedthis)同步代码块同样被锁定

当一个线程访问一个synchronizedthis)同步代码块时,其他线程可以访问该资源的非synchronizedthis)同步代码

线程安全的类型

方法是否同步 效率 适合场景
线程安全 多线程并发共享资源
非线程安全 单线程

为达到安全性和效率的平衡,可以根据实际场景来选择合适的类型

Hashtable 与 HashMap的区别

Hashtable:继承关系

1、实现了Map接口,Hashtable继承Dictionary

2、线程安全,效率较低

3、键和值都不允许为null

HashMap:继承关系

1、实现了Map接口,继承AbstractMap

2、非线程安全,效率较高

3、键和值都允许为null

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/97210.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!