Java高并发编程:定时器、互斥、同步通信技术

笔记摘要

这里分析了多线程的一些细节问题,并介绍了传统定时器的创建,同时实现了根据自己的调度计划的自定义定时器,对于传统互斥技术中发现的内部类问题,进行了分析,最后对于同步通信技术,是重点,分析了如何处理类似的问题,如何设计能够更加清晰简单,体现了高内聚和程序的健壮性

1. 多线程的几个知识点

1.1 为何使用实现Runnable的方式创建线程更普遍?

new Runnable()的方式,更加体现面向对象的思想

通过 new Thread()创建一个线程,代码封装在runnable对象中,代码和线程独立分开来,但最终将它们组合在一起。

Thread thread = new Thread(new Runnable() {

  @Override
  public void run() {
    // code
  }
});

1.2 获取线程名的时候,应使用currentThread().getName()方式

因为this.getName()方式,只有在当前对象是Thread的时候可以,当我们使用runnable方式时,this代表的是runnable对象,它仅是要运行代码的宿主,而不是线程,当然编译也无法通过(没有此方法)。

1.3 创建线程的两种传统方式的run方法执行问题

查看Thread类的run()方法的源代码,可以看到其实这两种方式都是在调用Thread对象的run()方法,如果Thread类的run()方法没有被覆盖,并且为该Thread对象设置了一个Runnable对象,该run方法会调用Runnable对象的run()方法。

下面是Thread类的run()方法的源码,可以看到runnable对象也是调用了Thread的run()方法。

当runnable对象不为null,并且有自己的run()方法,则执行自己的,如果target为null,则Thread类的run()方法什么也不执行,所以我们在创建线程的时候不直接创建Thread对象,而是创建其子类对象,目的是为了复写run方法,把要执行的代码放进去,否则该线程没有意义

Private Runnable target;  
public void run() {  
        if (target != null) {  
            target.run();  
        }  
}  

1.4 多线程的运行

问题1:如果在Thread子类覆盖的run()方法中编写了运行代码,也为Thread子类对象传递了一个Runnable对象,那么,线程运行时的执行代码?

是子类的run方法的代码?还是Runnable对象的run()方法的代码?如:

// 匿名内部类的方式实现的一个子类,并在构造方法中传入了一个Runnable对象
new Thread(new Runnable() {
  public void run() {
    // code
  }
}) {
  @Override
  public void run() {
    super.run();
    // code
  }
}.start();

会运行子类的run方法。因为当某个对象调用start方法之后,就会去找自己对象的run方法,如果没有就会找父类的run方法,父类的run方法会找runnable运行。

其实就是多态的一种体现,覆盖了父类的就执行自己的,没有覆盖就去找父类的执行

问题2:多线程机制是否会提高程序的运行效率?

多线程机制并不会提高程序的运行效率,反而性能更低,因为CPU需要在不同线程之间频繁切换。

1.5 多线程下载的误解?

多线程下载其实是抢了服务器的带宽,一个线程代表一个用户,每个线程分配的带宽是相等的,开启的线程多,就会分配更多的带宽,是在抢资源,而不是自己更快。

2. 传统定时器:Timer类

定时器有两种:一种在指定时间只执行一次,另一种先在指定时间执行一次,之后每隔指定时间循环执行。

该示例说明了定时器的创建方式,并通过自定义定时器的方式,在一个定时器内部通过不同切换秒数,来实现在不同的间隔时间实现循环爆炸,另外还通过两个类之间的互相实现相同的效果

import java.util.Date;  
import java.util.Timer;  
import java.util.TimerTask;  

public class TraditionalTimerTest {
     

    private static
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,可以使用synchronized关键字和wait()、notify()、notifyAll()方法来解决多线程之间的同步互斥问题。具体实现步骤如下: 1. 定义一个共享资源类,其中包含需要互斥访问的方法。 2. 在需要互斥访问的方法前加上synchronized关键字,表示该方法是同步方法。 3. 在访问共享资源时,使用wait()方法将当前线程挂起,直到其他线程执行notify()或notifyAll()方法唤醒它。 4. 在访问共享资源完毕后,使用notify()或notifyAll()方法唤醒其他线程。 下面是一个简单的例子,实现两个线程交替打印奇偶数: ```java class SharedResource { private int number = 1; private boolean isOdd = true; public synchronized void printOdd() { while (!isOdd) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(number); number++; isOdd = false; notify(); } public synchronized void printEven() { while (isOdd) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(number); number++; isOdd = true; notify(); } } public class Main { public static void main(String[] args) { SharedResource sharedResource = new SharedResource(); Thread thread1 = new Thread(() -> { for (int i = 0; i < 5; i++) { sharedResource.printOdd(); } }); Thread thread2 = new Thread(() -> { for (int i = 0; i < 5; i++) { sharedResource.printEven(); } }); thread1.start(); thread2.start(); } } ``` 在此例子中,首先定义了一个共享资源类SharedResource,其中包含了两个同步方法printOdd()和printEven(),分别用于打印奇数和偶数。 在printOdd()方法中,首先使用while循环判断是否可以打印奇数,如果不能,则使用wait()方法将当前线程挂起,等待其他线程唤醒它。如果可以打印奇数,则打印并将number加1,然后将isOdd设置为false表示下一个应该打印偶数,并使用notify()方法唤醒其他线程。 在printEven()方法中同理,只不过判断条件和操作的变量不同。 最后,在主函数中创建两个线程,分别调用printOdd()和printEven()方法,实现了奇偶数的交替打印。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值