Java实现多线程轮流打印1-100的数字操作

首先打印1-100数字如果用一个单线程实现那么只要一个for循环即可,那么如果要用两个线程打印出来呢?(一个线程打印奇数,一个线程打印偶数)于是大家会想到可以通过加锁实现,但是这样的效率是不是不高?这里我用一个变量来控制两个线程的输出

public class ThreadTest {
 volatile int flag=0;
 public void runThread() throws InterruptedException{
   Thread t1=new Thread(new Thread1());
   Thread t2=new Thread(new Thread2());
   t1.start();
   t2.start();
 }
 public class Thread1 implements Runnable{

 public void run() {
  int i=0;
  while(i<=99){
  if(flag==0)
  {
   System.out.println("t1="+i+"flag="+flag);
   i+=2;
   flag=1;
  }
  }
 }
 }

 public class Thread2 implements Runnable{

 public void run() {
  int i=1;
  while(i<=99){
  if(flag==1)
  {
   System.out.println("t2="+i+"flag="+flag);
   i+=2;
   flag=0;
  }
  }
 }

 }
}

那么如果要实现三个线程轮流打印1-100的数字呢?是不是也可以用上面的方法实现呢?代码如下

public class ThreadTest {
 private int i=0;
 private Thread thread1,thread2,thread3;
 private int flag=0;
 public void runThread() throws InterruptedException{
   thread1=new Thread(new Thread1());
   thread2=new Thread(new Thread2());
   thread3=new Thread(new Thread3());
   thread1.start();
   thread2.start();
   thread3.start();
 }
 public class Thread1 implements Runnable{

 public void run() {

  while(i<=100){
  if(flag==0) {
   System.out.println("t1="+i);
   i++;
   flag=1;
  }
  }
 }
 }

 public class Thread2 implements Runnable{

 public void run() {

  while(i<=100){
  if(flag==1) {
   System.out.println("t2="+i);
   i++;
   flag=2;
  }
  }
 }
 }

 public class Thread3 implements Runnable{

 public void run() {

  while(i<=100){
  if(flag==2) {
   System.out.println("t3="+i);
   i++;
   flag=0;
  }
  }
 }

 }
}

运行结果

发现三个线程只打印了一次就停止不输出了,是什么原因呢?

可以用jdk自带的jstack来看看线程的状态,在windows系统中可以打开cmd然后进入jdk所在目录,然后执行Jsp,能查看到各线程id,然后执行jstack -F pid就可以看的状态了

可以看到几个Thread state是BLOCKED,就是阻塞了,什么原因呢?

尴尬发现flag变量和i变量前面忘记加volatile,导致flag和i被线程读取修改时,其他线程不可见,所以才导致上面的问题出现。

在JVM中每个线程读取变量到cache中时相互都是不可见的,也就是java五大内存区中的程序计数器区域对于每个线程都是独立的不共享的,只有堆内存区和方法区是对所有线程都是共享的。

当线程1读取了flag和i的值,并对其进行修改的时候,线程2并发运行,并不知道flag和i值已经改变,导致多线程数据不一致的情况,所以加了volatile后,当线程读取变量进行修改后会“通知”其它线程这个值已经进行了修改。

import java.util.concurrent.atomic.AtomicInteger;
public class ThreadTest {
 private volatile int i=0;
 private Thread thread1,thread2,thread3;
 private volatile int flag=0;
 public void runThread() throws InterruptedException{
   thread1=new Thread(new Thread1());
   thread2=new Thread(new Thread2());
   thread3=new Thread(new Thread3());
   thread1.start();
   thread2.start();
   thread3.start();
 }
 public class Thread1 implements Runnable{

 public void run() {
  while(i<100){
  if(flag==0) {
   System.out.println("t1="+i);
   i++;
   flag=1;
  }
  }
 }

 }

 public class Thread2 implements Runnable{

 public void run() {

  while(i<100){
  if(flag==1){
   System.out.println("t2="+i);
   i++;
   flag=2;
  }
  }
 }

 }

 public class Thread3 implements Runnable{

 public void run() {

  while(i<100){
  if(flag==2){
   System.out.println("t3="+i);
   i++;
   flag=0;
  }
  }
 }

 }
}

运行结果

-----未完-----

补充知识:Java n个线程轮流打印数字的问题

一、两个线程轮流打印数字。

加锁实现:

package lianxi;

/*
 * 用锁实现两个线程轮流打印1——100
 */
public class Print1TO100TwoThread {
 private Object lock = new Object();
 private int i = 0;

 Thread threadA = new Thread(new Runnable() {
 @Override
 public void run() {
  while (i <= 100) {
  synchronized (lock) {

   try {
   if (i > 100)
    break;
   System.out.println("threadA :" + (i++));
   lock.notify();
   lock.wait();
   } catch (InterruptedException e) {
   e.printStackTrace();
   }
  }
  }
 }

 });

 Thread threadB = new Thread(new Runnable() {
 @Override
 public void run() {
  while (i <= 100) {
  synchronized (lock) {

   try {
   if (i > 100)
    break;
   System.out.println("threadB :" + (i++));
   lock.notify();
   lock.wait();
   } catch (InterruptedException e) {
   e.printStackTrace();
   }
  }
  }
 }
 });

 public void startTwoThread() throws InterruptedException {
 threadA.start();
 Thread.sleep(20);
 threadB.start();
 }
 public static void main(String[] args) throws InterruptedException {
 new Print1TO100TwoThread().startTwoThread();
 }
}

用锁效率太低,用一个变量来控制打印的顺序。

package lianxi;
/*
 * 用两个线程轮流打印1——10;用所实现效率太低,用变量来控制
 */
public class PrinntNumTwoThread {

 private volatile int num = 0;
 private volatile boolean flag = false;

 Thread threadA = new Thread(new Runnable() {

 @Override
 public void run() {
  while (true) {
  if (num > 10)
   return;
  if (!flag) {
   System.out.println("threadA-->" + ":" + (num++));
   flag = !flag;
  }
  }
 }

 });

 Thread threadB = new Thread(new Runnable() {
 @Override
 public void run() {
  while (true) {
  if (num > 10)
   return;
  if (flag) {
   System.out.println("threadB-->" + ":" + (num++));
   flag = !flag;
  }
  }
 }

 });

 public void startTwoThread() {
 threadA.start();
 threadB.start();
 }

 public static void main(String[] args) {
 new PrinntNumTwoThread().startTwoThread();
 }
}

二、那么如果要实现三个线程轮流打印1-100的数字呢?

package lianxi;
public class PrintNumThreeThread {
 private volatile int i = 0;
 private volatile int flag = 0;
 Thread threadA = new Thread(new Runnable() {
 @Override
 public void run() {
  while (true) {
  if (i > 100)
   return;
  if (flag == 0) {
   System.out.println("threadA->" + ":" + (i++));
   flag = 1;
  }
  }
 }

 });

 Thread threadB = new Thread(new Runnable() {
 @Override
 public void run() {
  while (true) {
  if (i > 100)
   return;
  if (flag == 1) {
   System.out.println("threadB->" + ":" + (i++));
   flag = 2;
  }
  }
 }

 });

 Thread threadC = new Thread(new Runnable() {
 @Override
 public void run() {
  while (true) {
  if (i > 100)
   return;
  if (flag == 2) {
   System.out.println("threadC->" + ":" + (i++));
   flag = 0;
  }
  }
 }
 });

 public void startThreeThread() {
 threadA.start();
 threadB.start();
 threadC.start();
 }

 public static void main(String[] args) {
 new PrintNumThreeThread().startThreeThread();
 }
}

以上这篇Java实现多线程轮流打印1-100的数字操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java常见面试题之多线程和高并发详解

    volatile 对 volatile的理解 volatile 是一种轻量级的同步机制. 保证数据可见性 不保证原子性 禁止指令重排序 JMM JMM(Java 内存模型)是一种抽象的概念,描述了一组规则或规范,定义了程序中各个变量的访问方式. JVM运行程序的实体是线程,每个线程创建时 JVM 都会为其创建一个工作内存,是线程的私有数据区域.JMM中规定所有变量都存储在主内存,主内存是共享内存.线程对变量的操作在工作内存中进行,首先将变量从主内存拷贝到工作内存,操作完成后写会主内存.不同线程间

  • Java利用future及时获取多线程运行结果

    Future接口是Java标准API的一部分,在java.util.concurrent包中.Future接口是Java线程Future模式的实现,可以来进行异步计算. 有了Future就可以进行三段式的编程了,1.启动多线程任务2.处理其他事3.收集多线程任务结果.从而实现了非阻塞的任务调用.在途中遇到一个问题,那就是虽然能异步获取结果,但是Future的结果需要通过isdone来判断是否有结果,或者使用get()函数来阻塞式获取执行结果.这样就不能实时跟踪其他线程的结果状态了,所以直接使用g

  • 详解Java Callable接口实现多线程的方式

    在Java 1.5以前,创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口.无论我们以怎样的形式实现多线程,都需要调用Thread类中的start方法去向操作系统请求io,cup等资源.因为线程run方法没有返回值,如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦. 而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果. Callable和Future介

  • Java实现多线程轮流打印1-100的数字操作

    首先打印1-100数字如果用一个单线程实现那么只要一个for循环即可,那么如果要用两个线程打印出来呢?(一个线程打印奇数,一个线程打印偶数)于是大家会想到可以通过加锁实现,但是这样的效率是不是不高?这里我用一个变量来控制两个线程的输出 public class ThreadTest { volatile int flag=0; public void runThread() throws InterruptedException{ Thread t1=new Thread(new Thread1

  • java实现多线程交替打印两个数

    本文实例为大家分享了java实现多线程交替打印两个数的具体代码,供大家参考,具体内容如下 方法1.使用wait和notify package com.thread; public class T01 { public static void main(String[] args) { char[] char1 = "AAAAAA".toCharArray(); char[] char2 = "BBBBBB".toCharArray(); Object object

  • java实现多线程交替打印

    本文实例为大家分享了java实现多线程交替打印的具体代码,供大家参考,具体内容如下 notify+wait实现 import org.junit.Test; import java.util.concurrent.*; public class TestThreadLocal { Object o = new Object(); CountDownLatch c=new CountDownLatch(2); @Test public void vvvvvvvv() throws Interrup

  • Java五种方式实现多线程循环打印问题

    目录 wait-notify join方式 ReentrantLock ReentrantLock+Condition Semaphore 三个线程T1.T2.T3轮流打印ABC,打印n次,如ABCABCABCABC- N个线程循环打印1-100- wait-notify 循环打印问题可以通过设置目标值,每个线程想打印目标值,如果拿到锁后这次轮到的数不是它想要的就进入wait class Wait_Notify_ABC { private int num; private static fina

  • Java多线程导致CPU占用100%解决及线程池正确关闭方式

    简介 情景:1000万表数据导入内存数据库,按分页大小10000查询,多线程,15条线程跑. 使用了ExecutorService executor = Executors.newFixedThreadPool(15) 本地跑了一段时间后,发现电脑CPU逐渐升高,最后CPU占用100%卡死,内存使用也高达80%. 排查问题 Debug 发现虽然创建了定长15的线程池,但是因为数据量大,在For中循环分页查询的List会持续加入LinkedBlockingQueue() 队列中每一个等待的任务,又

  • Java 实现多线程切换等待唤醒交替打印奇偶数

    引言 在日常工作生活中,可能会有用时几个人或是很多人干同一件事,在java编程中,同样也会出现类似的情况,多个线程干同样一个活儿,比如火车站买票系统不能多个人买一到的是同一张票,当某个窗口(线程)在卖某一张票的时候,别的窗口(线程)不允许再卖此张票了,在此过程中涉及到一个锁和资源等待的问题,如何合理正确的让线程与线程在干同一件事的过程中,不会抢资源以及一个一直等待一个一直干活的状况,接下来就聊一下多线程的等待唤醒以及切换的过程,在此就以A和B两个线程交替打印奇偶数的例子为例,代码如下: pack

  • Java Thread多线程开发中Object类详细讲解

    目录 方法概览 Thread wait  notify notifyAll方法详解 作用 阻塞阶段 唤醒阶段 遇到中断 代码展示 特点 通过wait notify方法实现生产者和消费者 sleep方法详解 sleep不会释放锁 sleep响应中断 总结 join方法详解 代码展示 yield方法 方法概览 Thread wait  notify notifyAll方法详解 作用 阻塞阶段 使用了wait方法之后,线程就会进入阻塞阶段,只有发生以下四种情况中的其中一个,线程才会被唤醒 另一个线程调

  • 详解Java实现多线程的三种方式

    本文实例为大家分享了Java实现多线程的三种方式,供大家参考,具体内容如下 import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class Main { public static void main(String[] args) { //方法一:继承Thread int i = 0; // for(; i < 100; i++){ // System.out.println(T

  • Java 实现多线程的几种方式汇总

    我们先来看段示例代码 import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class Main { public static void main(String[] args) { //方法一:继承Thread int i = 0; // for(; i < 100; i++){ // System.out.println(Thread.currentThread().getNa

  • java实现多线程的两种方式继承Thread类和实现Runnable接口的方法

    实现方式和继承方式有什么区别呢? *区别: *继承Thread:线程代码存放在Thread子类run方法中 *实现Runnable:线程代码存放在接口的子类的run方法中 *实现方式的好处:避免了单继承的局限性 *在定义线程时,建议使用实现方式,当然如果一个类没有继承父类,那么也可以通过继承Thread类来实现多线程 *注意:Runnable接口没有抛出异常,那么实现它的类只能是try-catch不能throws *Java对多线程的安全问题提供了专业的解决方式就是同步代码块synchroniz

随机推荐