Java高级特性:多线程

目录

多线程

主线程

线程的创建和启动

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、死亡状态

 线程调度:线程调度指按照特定机制为多个线程分配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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java多线程编程中,线程同步是一个非常重要的概念。它用来确保多个线程在访问共享资源时不会产生冲突或竞争条件。在Java中,有几种方式可以实现线程同步,其中之一就是使用synchronized关键字。 synchronized关键字可以用于修饰代码块或方法。当我们使用synchronized修饰代码块时,需要指定一个对象作为锁对象。在代码块内部,只有获取了锁对象的线程才能执行代码块中的内容,其他线程则需要等待。 在给定的示例中,synchronized关键字被用于修饰insert方法,这意味着同一时刻只能有一个线程能够执行这个方法。这样就确保了对num变量的访问是安全的,不会出现竞争条件导致数据不一致的情况。 具体来说,当一个线程进入synchronized修饰的insert方法时,它会获取到insertData对象的锁,并执行方法内部的代码。而其他线程则需要等待,直到当前线程释放了锁。这样就保证了对num变量的操作是线程安全的。 需要注意的是,synchronized关键字只能保证同一时刻只有一个线程能够执行被修饰的代码块或方法,但并不能保证线程的执行顺序。所以在多线程编程中,我们还需要考虑到线程的调度和执行顺序的不确定性。 除了synchronized关键字,Java还提供了其他的线程同步机制,比如Lock接口,它提供了更灵活和细粒度的线程同步控制。但是在大部分情况下,synchronized关键字已经能够满足我们的需求,使用它来实现线程同步是一种简单而有效的方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java高级特性 - 多线程基础(3)线程同步](https://blog.csdn.net/weixin_52034200/article/details/130253687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [EduCoder Java高级特性 - 多线程基础(3)线程同步](https://blog.csdn.net/weixin_45981481/article/details/114494972)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值