精华内容
下载资源
问答
  • 由此我产生了以下几个疑问: 1,JAVA的线程是抢占式的,但又遵守支持时间片的操作系统的时间片调度,那么这里的抢占与时间片轮换之间又有怎样的关系,是怎么协调的? 2,每个线程的时间片分配大小是否相等? 3,...

    如下程序publicclassThreadTest{publicstaticvoidmain(String[]args){MyThreadth=newMyThread();newThread(th).start();newThread(th).start();newThread(th).start();newThread(th)....

    如下程序

    public class ThreadTest {

    public static void main(String[] args) {

    MyThread th=new MyThread();

    new Thread(th).start();

    new Thread(th).start();

    new Thread(th).start();

    new Thread(th).start();

    }

    }

    class MyThread implements Runnable {

    int tickets = 20;

    Object obj = new Object();

    public void run(){

    while(true){

    synchronized(obj){

    if(tickets > 0){

    try {

    Thread.sleep(10);

    } catch (InterruptedException e) {

    // TODO 自动生成 catch 块

    e.printStackTrace();

    }

    System.out.println("现在卖第"+tickets+"张 买卖票窗口:"+Thread.currentThread().getName());

    tickets--;

    }

    else{

    System.out.println("窗口"+Thread.currentThread().getName()+"票已经卖完");

    break;

    }

    }

    }

    }

    }

    由时间片分配可知运行的结果应该是各个线程运行同样的时间,卖出同样的票啊,但结果却是这样的

    现在卖第20张 买卖票窗口:Thread-0

    现在卖第19张 买卖票窗口:Thread-3

    现在卖第18张 买卖票窗口:Thread-3

    现在卖第17张 买卖票窗口:Thread-3

    现在卖第16张 买卖票窗口:Thread-3

    现在卖第15张 买卖票窗口:Thread-3

    现在卖第14张 买卖票窗口:Thread-2

    现在卖第13张 买卖票窗口:Thread-2

    现在卖第12张 买卖票窗口:Thread-2

    现在卖第11张 买卖票窗口:Thread-2

    现在卖第10张 买卖票窗口:Thread-1

    现在卖第9张 买卖票窗口:Thread-2

    现在卖第8张 买卖票窗口:Thread-2

    现在卖第7张 买卖票窗口:Thread-2

    现在卖第6张 买卖票窗口:Thread-2

    现在卖第5张 买卖票窗口:Thread-2

    现在卖第4张 买卖票窗口:Thread-2

    现在卖第3张 买卖票窗口:Thread-3

    现在卖第2张 买卖票窗口:Thread-3

    现在卖第1张 买卖票窗口:Thread-3

    窗口Thread-3票已经卖完

    窗口Thread-0票已经卖完

    窗口Thread-2票已经卖完

    窗口Thread-1票已经卖完

    有的卖的多有的卖的少。

    由此我产生了以下几个疑问:

    1,JAVA的线程是抢占式的,但又遵守支持时间片的操作系统的时间片调度,那么这里的抢占与时间片轮换之间又有怎样的关系,是怎么协调的?

    2,每个线程的时间片分配大小是否相等?

    3,以上程序中的线程为什么不是依次的执行,比如Thread-0执行后应该是Thread-1执行,但结果确实Thread-3在执行,当Thread-0睡眠过后,执行剩余的代码,外面等待的应该是Thread-2啊,那怎么会执行Thread-3呢?

    4,为什么每个线程的执行时间不是一样的长?

    期盼大家能帮下我--一个渴望学习JAVA的初学者

    展开

    展开全文
  • 文章目标当Java项目出现性能瓶颈的时候,通常先是对资源消耗做分析,包括CPU,文件IO,网络IO,内存;之后再结合相应工具查找消耗主体的程序代码。本文主要介绍系统资源消耗的分析过程,...上下文切换每个CPU(或多核...

    文章目标

    当Java项目出现性能瓶颈的时候,通常先是对资源消耗做分析,包括CPU,文件IO,网络IO,内存;之后再结合相应工具查找消耗主体的程序代码。本文主要介绍系统资源消耗的分析过程,以及常用的Java线程分析方法。

    CPU分析

    在Linux中,CPU主要用于处理中断、内核及用户任务,优先级为:中断>内核>用户。在分析CPU消耗状况的时候,需要了解以下三个概念。

    上下文切换

    每个CPU(或多核CPU的每个核心)在同一时间只能执行一个线程,Linux采用抢占式调度。当线程执行到达一个时间片后有高优先级线程要执行,或者线程有IO阻塞的时候,或者有线程中断的时候,又或者有锁资源竞争阻塞(sleep不涉及锁资源竞争)或者用户挂起线程(如wait())的时候Linux将执行线程切换,切换前先保存当前线程执行状态(现场),并恢复待执行线程状态,这个过程就叫做上下文切换。在Java应用中,文件IO、网络IO、锁等待、线程Sleep操作都会使该线程进行阻塞或睡眠状态,从而触发上下文切换。频繁的上下文切换会造成内核占用较高的CPU,使得响应速度下降。

    运行队列

    每个CPU核心都维护了一个可运行队列,例如一个4核CPU,启动8个线程,且8个线程都处于可运行状态,平均分配情况下,每个核心的可运行队列里就有2个线程。通常而言,系统的load是由CPU运行队列决定的,假设以上状态维持了1分钟,则1分钟内系统load就是2。运行队列值越大,代表线程要消耗越长的时间才能执行完成。通常建议每个核心运行队列为1-3个。

    利用率

    CPU利用率指在用户进程,内核,中断处理,IO等待以及空闲五个部分百分比,这五个值是用来分析CPU消耗情况的关键指标。Linux System and NetWork Performent Monitoring建议用户进程/内核消耗比例为 65%-70% / 30%-35% 左右。

    常用top, pidstat, sar, vmstat 1 分析占用情况,下图是top示例

    us:用户进程处理占用百分比

    sy:内核线程处理占用百分比

    ni:被nice命令改变优先级的任务所占百分比

    id:cpu空闲时间占用百分比

    wa:在执行过程中等待IO所占百分比

    hi:硬件中断占用百分比

    si:软件中断占用百分比

    st:虚拟机偷取时间百分比

    对Java应用而言,线程消耗主要体现在us, sy上:

    us: 用户进程处理占用百分比

    us占用分析,需要依靠相关命令找出主体消耗线程ID(tid),然后转化成十六进制(printf "%x\n" tid),再用 kill -3 java_pid或 jstack -l java_pid 命令dump出线程信息,通过之前的十六进制值在dump信息中找到nid相等的线程,即为消耗CPU的线程。采样的时候要多做几次,保证找到的是真实的消耗线程。

    在Java应用中如果us占用过高,代表运行的应用程序消耗了大部分CPU,常见为线程一直处理可运行状态(Runnable),并且无阻塞地执行循环,正则或复杂计算;也可能是每次请求都分配大量内存,导致频繁GC甚至频繁FullGC造成的,这时就需要依靠jvm工具查看了(jps, jmap, jstat等) 。

    sy: 内核线程处理占用百分比

    sy值过高表示Linux花费大量时间在线程切换上,Java造成原因通常是启动大量线程,且多数线程处理不断阻塞(如IO等待,锁等待)和执行的状态变化中,造成大量上下文切换。这时可通过 kill -3 java_pid或jstack -l java_pid 命令dump出线程信息,找出不断切换线程执行状态的原因(也可以通过TDA分析)。

    如下使用 vmstat 1 查看上下文切换(cs)及sy占用

    如果cs值很高的话,再使用 jstack -l java_pid 查看线程堆栈信息,通常可以发现大量线程处于TIMED_WAITING (on object monitor)与Runnable状态转化中,通过on object monitor可以找到锁竞争激烈的代码,从而找出上下文切换的原因。

    文件IO分析

    Linux在操作文件的时候,会将文件放入文件缓存区,直到内存不够或系统要释放内存给用户进程使用时,才会交换出去。因此在查看内存状态时经常发现可用(free)的物理内存不足,但cached用了很多,这是Linux提升文件IO速度的一种方法。这种情况下,如果物理内存足够用,真正的文件IO只有写文件和第一次读的时候才会产生。

    在Linux中文件IO主要通过 pidstat, iostat分析:

    pidstat -d -p java_pid 1 3

    KB_rd/s 表示每秒读取的KB数, KB_wr/s表示每秒写入的KB数, 还可以加入-t参数显示具体的线程信息。

    iostat

    iostat只能看到整个系统的文件IO,不能查看具体进程消耗情况。Device表示设备卷标名或分区名,tps是每秒的IO请求,是IO消耗关键指标;Blk_read/s表示每秒读的块数量,Blk_wrtn/s表示每秒写的块数量;Blk_read, Blk_wrtn表示总共读写的块数量;当%iowait占用很高的时候,就要关注IO消耗状况了,这时可以使用 iostat -x 观察:

    r/s, w/s 表示每秒读写的请求数, await表示平均每次IO操作的等待时间,avgqu-sz表示等待请求的队列的平均长度,svctm表示平均每次设备执行IO操作的时间,util表示一秒之中有百分之几用于IO操作。

    在Java应用中造成文件IO消耗严重的原因,通常是多个线程进行大量写入操作(如频繁写入日志文件)。这时可以通过pidstat或iostat结合jstack线程信息,找到消耗主体程序。

    网络IO分析

    在分布式Java应用中,网络IO的消耗是非常值得关注的,尤其注意网卡中断是不是均匀地分配到各CPU上(cat /proc/interrupts)。Linux使用sar分析网络IO消耗情况:

    sar -n ALL 1 2

    主要观注接包(rxpck/s),发包(txpck/s),接包失败(rxerr/s),发包失败(txerr/s),丢包(rxdrop/s),Socket信息(tcpsck , udpsck)。

    由于无法观察具体进程的网络IO消耗,在网络IO消耗高时,只能线程dump,通常这些线程都在进行网络读写操作。在Java网络通信中,通常将对象序列化为字节流发送,反序列化生成对象。

    内存分析

    从Java应用角度上看,内存可分为两部分,即JVM内存与非JVM内存。在JVM中内存消耗主要体现在堆内存上,内存消耗过高会导致频繁GC甚至FullGC,CPU占用高,可以通过jmap, jstat, mat, visualvm等工具跟踪内存消耗情况;生产环境下,通常将 -Xms 和 -Xmx调整为相同的值,避免运行时不断申请内存。非JVM内存通常只有在创建线程或使用DirectByteBuffer时才会产生,最值得关注的是swap的消耗与物理内存的消耗。

    vmstat

    swpd表示虚拟内存已使用的部分(kb),free空闲物理内存,buff表示用于缓冲的内存,cache表示用于作为缓存的内存。swap下的si表示每秒从disk读到内存的数据量,so每秒从内存写入disk的数据量。swpd过高表示物理内存不够用,系统需要频繁从虚拟内存与disk交换数据,严重影响系统的性能。

    sar -r 2 5

    通过sar工具可以看到内存占用,空闲,buff, cache的情况。当物理内存空闲时,Linux会使用一部分内存用于buffer以及cache,以提高系统运行效率。因此可认为系统可用物理内存为 kbmemfree + kbbuffers + kbcached。

    此外还可以使用top, pidstat -r -p [pid][interval][times]

    pidstat -r -p 2448 1 5

    参考资料

    中断:http://blog.csdn.net/pxz_002/article/details/7327668

    CPU占用分析:http://www.cnblogs.com/yjf512/p/3383915.html

    林昊:分布式Java应用

    JVM内存分析:http://my.oschina.net/feichexia/blog/196575

    https://wenku.baidu.com/view/c7c38dbe4b35eefdc8d333a8.html

    展开全文
  • Java线程状态及切换

    2021-03-14 18:14:45
    Java线程状态及切换一、什么是Java线程状态在Java程序中,用于描述Java线程的六种状态:新建(NEW):当前线程,刚刚新建出来,尚未启动。运行(RUNNABLE):当前线程,处于竞争CPU时间分片或已经获得CPU时间片的状态。...

    Java线程状态及切换

    一、什么是Java线程状态

    在Java程序中,用于描述Java线程的六种状态:

    新建(NEW):当前线程,刚刚新建出来,尚未启动。

    运行(RUNNABLE):当前线程,处于竞争CPU时间分片或已经获得CPU时间片的状态。

    等待(WAITTING):当前线程,处于休眠,不参与CPU时间片竞争的状态。

    定时等待(TIMED_WAITTING):当前线程,处于定时休眠,暂时不参与CPU时间片竞争的状态。

    阻塞(BLOCKED):当前线程,处于阻塞,不参与CPU时间片竞争的状态。

    终止(TERMINATED):当前线程,处于最终停止的状态。

    新建状态,只能进入运行状态。而终止状态无法再转为其他状态。

    等待/定时等待与阻塞,差别就是后者需要一个事件信号(如其他线程放弃当前线程需要的排他锁),才可以进行状态切换。当然,强行关闭也是可以的。

    Java线程的实现并不受JVM规范约束,故不同虚拟机的实现,往往不同。目前主流的HotSpot是将每个Java线程直接映射到一个操作系统的原生线程,从而由操作系统完成一系列的线程调度

    二、哪里看Java线程状态

    查看Java线程状态,主要存在三种方式:

    java.lang.Thread.State下可以直接看到Java的六种线程状态

    Java运行时,程序内部可以通过Thread.getState()获取目标线程状态

    Java运行时,程序外部可以通过jstack等工具,查看线程状态

    有关jstack等工具等使用,后续会有博客,专门阐述。

    三、什么时候变换Java线程状态

    Java线程状态的切换嘛。不啰嗦,直接上图。

    dcfab5f39579f0db7c1873330229e2e6.png

    这张图涵盖了Java线程状态切换的各类方法。相较网上一些图片,更为详尽一些。

    如果有所遗漏,可以告诉我,我会及时填补上。

    四、谁在使用Java线程状态

    日常开发中,我们并不会直接与线程状态进行交互。

    我们往往直接使用JDK包装好的工具,如JUC包下的各类工具等。

    举个栗子

    线程池中的应用

    位置:com.sun.corba.se.impl.orbutil.threadpool.ThreadPoolImpl#close

    // Note that this method should not return until AFTER all threads have died.

    public void close() throws IOException {

    // Copy to avoid concurrent modification problems.

    List copy = null;

    synchronized (workersLock) {

    copy = new ArrayList<>(workers);

    }

    for (WorkerThread wt : copy) {

    wt.close();

    while (wt.getState() != Thread.State.TERMINATED) {

    try {

    wt.join();

    } catch (InterruptedException exc) {

    wrapper.interruptedJoinCallWhileClosingThreadPool(exc, wt, this);

    }

    }

    }

    threadGroup = null;

    }

    实际查看JDK后发现,JDK中其实也没有辣么多的实例,并且大多数直接关联线程状态的,也是一些状态查看的东东。

    这在文章开头就说,Java线程操作,是很底层的,甚至其实现都不包含在虚拟机规范中。

    主流的HotSpot,也是直接将Java线程映射到系统线程,由系统进行一系列的线程调度处理。

    所以,在JDK中,是直接对线程状态进行处理的部分是很少的。

    五、为什么需要线程状态

    1.为什么需要线程状态这一概念

    这个问题,可以从两个角度来说明:生命周期与资源管理

    一方面,线程状态很好地刻画了线程的整个生命周期,对生命周期中不同阶段进行了有效划分。

    另一方面,资源是有限的,需求是无限的。所以需要将系统资源有意识地进行调度,合理利用比较优势,追求帕累托最优。

    实现后者的,就是利用线程在生命周期的不同阶段这一天然属性带来的状态刻画,进行的分组。CPU调度只需要关注运行状态的线程。而阻塞,等待等线程,都有着属于自己的一套处理方式。最终获得资源(开发时对复杂性的应对,运行时对系统资源对消耗,应用者心智模型的成长等)的优化分配。

    2.JDK中为什么需要定义Java线程状态

    前文有说到,Java中很少直接使用到线程状态。那么为什么还要在JDK中定义Java的六种线程状态呢?

    一方面,通过信息透明的方式,降低使用者使用时建立心智模型的成本。如,现在的我们可以通过打印日志,打断点,快速了解Java的各个线程状态,并清楚了解产生的原因。从而大大提高了我们对Java线程的认识,进而更为愉快地拥抱JUC包下诸如线程池等工具。

    另一方面,通过可以直接应用的状态枚举,我们可以很好地对现有工具进行二次开发等。如我们可以通过扩展AQS,并在其中添加线程状态的校验,从而得到定制化的线程同步工具。

    六、如何使用线程状态

    使用的方式,我已经在上文说了:学习Java线程,定制线程相关工具开发。

    这里给出一个有关线程学习的demo:

    /**

    * @program: learning

    * @description: 用于确认线程状态问题

    * @author: Jarry

    * @create: 2020-10-26 22:25

    **/

    public class ThreadState {

    public static void main(String[] args) {

    threadStateTest();

    // threadStateTest2();

    // threadStateWithBlocked();

    // threadStateWithException();

    // threadStateWithSuspend();

    }

    /**

    * 实践证明:Thread.suspend()与Thread.resume()不会改变线程状态

    * 线程状态该是Waiting,就Waiting。该Timed_Waiting就Timed_Waiting

    * Thread.suspend()与Thread.resume()只是挂起目标线程(并且不会释放锁资源)

    */

    private static void threadStateWithSuspend() {

    Thread thread1 = new Thread(() -> {

    // LockSupport.park();

    LockSupport.parkNanos(2000000000);

    });

    thread1.start();

    printThreadState(thread1);

    LockSupport.parkNanos(500000000);

    printThreadState(thread1);

    thread1.suspend();

    printThreadState(thread1);

    LockSupport.parkNanos(500000000);

    printThreadState(thread1);

    thread1.resume();

    LockSupport.parkNanos(500000000);

    printThreadState(thread1);

    // LockSupport.unpark(thread1);

    }

    /**

    * 展现线程阻塞状态

    */

    private static void threadStateWithBlocked() {

    Runnable runnable = new Runnable() {

    @Override

    public void run() {

    synchronized (ThreadState.class) {

    // LockSupport.parkNanos(2000000000);

    LockSupport.park();

    }

    }

    };

    Thread thread1 = new Thread(runnable);

    Thread thread2 = new Thread(runnable);

    thread1.start();

    LockSupport.parkNanos(500000000);

    thread2.start();

    // 加上以下时间间隔,则结果:Runnable->Blocked

    // 推论:Thread.start()会将线程状态设置为Runnable,然后在遇到sync的锁,再切换为Blocked状态

    // LockSupport.parkNanos(500000000);

    printThreadState(thread2);

    LockSupport.parkNanos(500000000);

    printThreadState(thread2);

    LockSupport.parkNanos(500000000);

    LockSupport.unpark(thread1);

    LockSupport.unpark(thread2);

    }

    /**

    * 由于底层实现机制的不同(相较于其他waiting的方法),无法直接进行Object.wait(),否则会抛出以下异常

    * @exception java.lang.IllegalMonitorStateException

    * object.wait()进行wait的方法,是直接对其wait_set进行操作

    */

    private static void threadStateWithException() {

    Thread thread1 = new Thread(() -> {

    try {

    ThreadState.class.wait(2000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    });

    thread1.start();

    LockSupport.parkNanos(1000000000);

    printThreadState(thread1);

    }

    /**

    * Object.wait()的使用

    */

    private static void threadStateTest3() {

    Thread thread1 = new Thread(() -> {

    synchronized (ThreadState.class) {

    try {

    ThreadState.class.wait(2000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    });

    thread1.start();

    LockSupport.parkNanos(1000000000);

    printThreadState(thread1);

    }

    /**

    * 确定LockSupport.parkNacos()是否可以生成Time_Waiting状态

    */

    private static void threadStateTest2() {

    Thread thread1 = new Thread(() -> {

    LockSupport.parkNanos(2000000000);

    });

    thread1.start();

    printThreadState(thread1);

    LockSupport.parkNanos(1000000000);

    printThreadState(thread1);

    }

    /**

    * 查看到除Blocked以外的所有线程状态

    */

    private static void threadStateTest() {

    Thread thread1 = new Thread(() -> {

    synchronized (ThreadState.class) {

    // Runnable

    printThreadState(Thread.currentThread());

    // 1.Thread.sleep(time)

    try {

    Thread.sleep(2000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    // 2.Object.wait(time)

    // try {

    // ThreadState.class.wait(2000);

    // } catch (InterruptedException e) {

    // e.printStackTrace();

    // }

    // 3.Thread.join(time)

    // try {

    // Thread.currentThread().join(2000);

    // } catch (InterruptedException e) {

    // e.printStackTrace();

    // }

    // 4.LockSupport.parkNanos(time);

    // LockSupport.parkNanos(2000000000);

    // 5.LockSupport.parkUntil(timeStamp);

    // LockSupport.parkUntil(System.currentTimeMillis()+2000);

    LockSupport.park();

    }

    });

    thread1.setName("test_thread");

    // New

    printThreadState(thread1);

    thread1.start();

    LockSupport.parkNanos(1000000000);

    // Timed_waiting

    printThreadState(thread1);

    LockSupport.parkNanos(2000000000);

    // Waiting

    printThreadState(thread1);

    LockSupport.unpark(thread1);

    LockSupport.parkNanos(1000000000);

    // Terminated

    printThreadState(thread1);

    }

    private static void printThreadState(Thread thread) {

    System.out.println("current Thread(" + thread.getName()+":" + thread.getId() + ") state:" + thread.getState());

    }

    }

    代码中有一些细碎的知识点,就不在这里赘述了。感兴趣的小伙伴,可以自己看看注释,自行验证。

    七、扩展:系统状态(三态&五态)

    操作系统就包含进程管理,作业管理,文件管理等。其中进程管理,就涉及系统状态的三态模型与五态模型。

    其中,三态模型包含以下三种状态:

    就绪状态

    运行状态

    阻塞状态

    而五态模型则包含以下五种状态:

    运行状态

    静止就绪态

    活跃就绪态

    静止阻塞态

    活跃阻塞态

    具体状态切换等,可以看我之前写的一篇博客:

    系统架构设计师-操作系统

    最后,愿与诸君共进步。

    八、附录

    补充:WAITTING/TIMED_WAITTING与BLOCKED的区别

    其实,我之前也挺纠结这个问题的。

    当时的想法是WAITTING/TIMED_WAITTING是由JVM自己维持,而BLOCKED是由系统维持的。后面看到主流的HotSpot是将线程映射到系统原生线程的,所以这个想法大概率是错误的。

    那么两者区别是什么呢?

    直到我在上文的示例代码中,BLOCKED状态的线程,在其他线程释放其所需的锁时,该线程是先转为RUNNING状态,再变为其他状态。这引起我的注意。

    最后在stackOverFlow的一篇文章(Difference between WAIT and BLOCKED thread states)中,看到这样的解释:

    The important difference between the blocked and wait states is the impact on the scheduler. A thread in a blocked state is contending for a lock; that thread still counts as something the scheduler needs to service, possibly getting factored into the scheduler's decisions about how much time to give running threads (so that it can give the threads blocking on the lock a chance).

    Once a thread is in the wait state the stress it puts on the system is minimized, and the scheduler doesn't have to worry about it. It goes dormant until it receives a notification. Except for the fact that it keeps an OS thread occupied it is entirely out of play.

    This is why using notifyAll is less than ideal, it causes a bunch of threads that were previously happily dormant putting no load on the system to get woken up, where most of them will block until they can acquire the lock, find the condition they are waiting for is not true, and go back to waiting. It would be preferable to notify only those threads that have a chance of making progress.

    (Using ReentrantLock instead of intrinsic locks allows you to have multiple conditions for one lock, so that you can make sure the notified thread is one that's waiting on a particular condition, avoiding the lost-notification bug in the case of a thread getting notified for something it can't act on.)

    简单说,就是CPU时间片不会考虑WAITTING/TIMED_WAITTING状态。

    但是,虽然BLOCKED状态的线程无法获得CPU时间片,但是系统调度时,依旧会考虑BLOCKED状态的线程,将其置于调度计算中。

    如果哪位小伙伴对这方面有了解,希望可以聊一聊。

    参考

    展开全文
  • 目标:Number线程类执行数字的递增并输出,并且没增加两个就切换到另外一个线程,Letter线程类执行字母的递增并输出,并且没输出一个就切换到另外一个线程。主类:public static void main(String[] args) {Print ...

    目标:Number线程类执行数字的递增并输出,并且没增加两个就切换到另外一个线程,Letter线程类执行字母的递增并输出,并且没输出一个就切换到另外一个线程。

    主类:

    public static void main(String[] args) {

    Print print = new Print();

    Number number = new Number(print);

    Letter letter = new Letter(print);

    Thread thread = new Thread(number);

    Thread thread2 = new Thread(letter);

    thread.start();

    thread2.start();

    }

    数字类:

    private Print print;

    /**

    * 带参数的构造方法传入 print对象 确保两个线程类操作的是同一个对象

    *

    * @param print

    */

    public Number(Print print) {

    super();

    this.print = print;

    }

    @Override

    public void run() {

    if (print.getTemp()) {//如果符合条件就往下执行

    synchronized (print) {//该对象获得锁

    for (int i = 1; i <= 52; i++) {

    System.out.println(i);

    if (i % 2 == 0) {

    try {

    print.setTemp(false);//首先把标志更改

    print.notifyAll();//唤醒其他所有正在等待的线程

    print.wait();//并把此线程处于等待状态

    print.notify();//唤醒此线程,防止程序执行到最后仍处于未停止状态

    } catch (InterruptedException e1) {

    e1.printStackTrace();

    }

    }

    }

    }

    }

    }

    字母类:

    private Print print;

    public Letter(Print print) {

    super();

    this.print = print;

    }

    @Override

    public void run() {

    if (!print.getTemp()) {

    synchronized (print) {

    for (int i = 65; i <= 90; i++) {

    System.out.println((char) i);

    try {

    print.setTemp(true);

    print.notifyAll();

    print.wait();

    print.notify();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }

    标识类:

    private boolean temp = true;

    public boolean getTemp() {

    return temp;

    }

    public void setTemp(boolean temp) {

    this.temp = temp;

    }

    展开全文
  • 如果起一个线程(模拟没有线程切换),完成任务需要多长时间?如果起5个线程,完成任务需要消耗多久时间?如果起20个线程,完成任务需要多长时间?如果起20个线程呢?20个线程呢?50个线程呢?假设1:cpu是单核cpu假设...
  • 1、上下文切换就是一个线程释放处理器的使用权,...2、在 JDK 的 java.lang.Thread.State 源码中定义了6个状态,在某一时刻,一个线程只能处于一种状态:New、Runnable、Blocked、Waiting、Timed Waiting、Terminated
  • 我们的应用程序以UTC时区存储所有日期....即2013年10月31日星期四,UTC时间23:00:0和2013年11月29日星期五,格林威治标准时间23:00:00开始的时间段应该全球称为11月13日,对于我们的主要业务部门,时代将会...
  • 前言本文要说的是基于 keepalived 实现两台服务器之间的主备切换,从而实现 Java 服务的高可用。keepalived 的原理不多做介绍,自行搜索了解,keepalived 的安装部署请参考 keepalived 的安装及使用 。个人建议不要...
  • 在操作系统中,上下文切换的类型还可以分为进程间的上下文切换和线程间的上下文切换。而在多线程编程中,我们主要面对的就是线程间的上下文切换导致的性能问题,下面我们就重点看看究竟是什么原因导致了多线程的上...
  • 前言项目中有需求是实现类似与手机中勿扰模式的逻辑,判断当前时间点是否属于指定时间段(24H)。实现思路获取当前时间、开始时间、结束时间的小时数hour、分钟数minute首先比较hour,i. endHour > startHour,即...
  • 对于上下文切换不同的操作系统模式也不尽...时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的,时间片一般是几十毫秒(ms)CPU通过时间片分配算...
  • java中的时间操作 三 定时任务关于定时任务,似乎跟时间操作的联系并不是很大,但是前面既然提到了定时任务,索性在这里一起解决了。设置定时任务很简单,用Timer类就搞定了。一、延时执行首先,我们定义一个类,给...
  • import java.text.*;...public class VeDate {/*** 获取现在时间** @return 返回时间类型 yyyy-MM-dd HH:mm:ss*/public static Date getNowDate() {Date currentTime = new Date();SimpleDateFormat form...
  • Java线程上下文切换

    2020-12-23 15:10:37
    虽然并不是真正意义上的“同一时间点”,而是 多个任务或进程共享一个CPU,并交由操作系统来完成多任务间对CPU的运行切换,以使得每个任务都有机会获得一定的时间片运行。 再后来发展到多线程技术,使得在一个程序...
  • 我需要在Ctrl-Tab和Ctrl-Shift-Tab上切换选项卡。但是它仅在TabPane处于焦点时才起作用。我有带有setContent(textArea)的标签页。当textArea成为焦点时,然后按Ctrl-Tab,焦点将移至菜单中的某个位置:TextArea@3f40...
  • Java多线程上下文切换

    2021-02-12 18:30:25
    一:什么是上下文切换CPU处理任务时不是一直只处理一个,而是通过给每个线程分配CPU时间片,时间片用完了就切换下一个线程。时间片非常短,一般只有几十毫秒,所以CPU通过不停地切换线程执行时我们几乎感觉不到任务...
  • 默认redis使用的是db 0,而我们自己在配置连接的时候可以设置默认使用db ,如:那么怎么去实现动态去切换自己想使用的db呢?LettuceConnectionFactory connectionFactory = (LettuceConnectionFactory) ...
  • import java.util.Set;import java.util.concurrent.TimeUnit;import org.junit.jupiter.api.AfterEach;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.Test;import org.openqa.selenium.By...
  • 通常可以设置某个固定的切换时间,之后显示固定的或者是随机的显示某张图片,举例:import java.awt.*;import java.awt.event.*;import javax.swing.*;public class MousDemo extends JFrame {MyJPanel mp;int index...
  • java - 如何获取一天的开始时间和结束时间?如何获得一天的开始时间和结束时间?这样的代码不准确:private Date getStartOfDay(Date date) {Calendar calendar = Calendar.getInstance();int year = calendar.get...
  • linux jdk版本随时切换

    2021-02-12 20:00:57
    fordreamxin@compiler207:~$ whichjava/usr/bin/java/usr/bin/目录下存放的多是用户安装的软件fordreamxin@compiler207:~$ ll /usr/bin/javalrwxrwxrwx1 root root 22 Nov 13 06:18 /usr/bin/java -> /etc/...
  • Java实现多种幻灯片切换特效(附源码)以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!功能说明 代码实现了多种幻灯片变换特效 如 淡入淡出 缓慢覆蓋 ...
  • 最近开发环境由之前的java环境切换到PHP,生成的时间戳转换成时间出现异常,查了一些资料,得知: PHP的 time() 函数返回的结果是 Unix 时间戳,值的单位是秒;如:1463564861 Java 中System.currentTimeMillis() ...
  • import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.AbstractButton;import javax.swing.JFrame;import javax.swing.JToggleButton;public ...
  • // 毫秒时间戳转换为日、时、分、秒 public static String timeStampToDhms(long milliseconds) { long day = TimeUnit.MILLISECONDS.toDays(milliseconds); long hours = TimeUnit.MILLISECONDS.toHours...
  • 下面就是我这段时间在忙的一部分内容 一个成熟的商城,必定是全能的,啥都能卖,那么一套UI肯定是搞不定的。但UI模板多了也就更难维护了,有没有更简单的方式呢?看下文。 一键换色是个啥 **目的:**迎合各行各业和...
  • 一些闲扯的话我们清楚,Redis 尽管提供了 16 个索引库,但是每个数据库...所以,本文切换数据库是基于单机版 Redis 的。为什么 Redis 要有这么多的数据库,以及为啥要切换?个人理解 ,Redis 之所以分这么多个数据库...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 322,187
精华内容 128,874
关键字:

java的时间切换

java 订阅