Java多线程经典编程题

Java多线程经典编程题

1. 要求线程a执行完才开始线程b, 线程b执行完才开始线程

package com.example.javatest.theardTest.MultiThreadAlgorithm;

/**

  • 要求线程a执行完才开始线程b, 线程b执行完才开始线程
  • join()解释:https://blog.csdn.net/qq_18505715/article/details/79795728
  • wait() 和 notify() 解释:https://blog.csdn.net/chaozhi_guo/article/details/50249177
  • join()的作用:主要作用是同步,它可以使得线程之间的并行执行变为串行执行。在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。
  • public void joinDemo(){
  • //....
  • Thread t=new Thread(payService);
  • t.start();
  • //....
  • //其他业务逻辑处理,不需要确定t线程是否执行完
  • insertData();
  • //后续的处理,需要依赖t线程的执行结果,可以在这里调用join方法等待t线程执行结束
  • t.join();
  • }

*/
public class T1T2T3 {

public static class PrintThread extends Thread{

    PrintThread(String name){
        super(name);
    }

    @Override
    public void run() {
        for(int i = 0; i < 100; i++){
            System.out.println(getName() + " : " + i);
        }
    }
}

public static void main(String[] args){

    PrintThread t1 = new PrintThread("a");
    PrintThread t2 = new PrintThread("b");
    PrintThread t3 = new PrintThread("c");

    try {

        t1.start();
        t1.join();

        t2.start();
        t2.join();

        t3.start();
        t3.join();

    } catch (InterruptedException e) {
        e.printStackTrace();
    }


}

}

/**

  • 我对于join方法的理解:
  • join() 的源码:
  • public final void join(long millis) throws InterruptedException {
  •     synchronized(lock) {
    
  •     ...
    
  •       while (isAlive()) {
    
  •          lock.wait(0);
    
  •       }
    
  •    ...
    
  •     }
    
  • }
  • 其实就是main()线程调用join()后,synchronized(lock)语句块,获得lock的锁,
  • 然后判断如果t1线程isAlive(), 就一直lock.wait(), 让自己(main()线程)阻塞住,
  • 直到t1线程 !isAlive 后才不wait, 等待着被notify(), 然后t1 die后会调用lock.notifyAll()。
  • 注意:这里lock.wait(0)虽然在t1.join()内,但是join()内的代码不是运行在t1线程中,而是运行在main()线程中,
  •      t1线程中运行的是其run()方法内的代码。
    

*/

2. 两个线程轮流打印数字,一直到100

package com.example.javatest.theardTest.MultiThreadAlgorithm;

/**
 * 两个线程轮流打印数字,一直到100
 * 
 * Java的wait()、notify()学习:
 * https://blog.csdn.net/boling_cavalry/article/details/77995069
 https://blog.csdn.net/boling_cavalry/article/details/77793224 wait()和notify()的通常用法
 */
public class TakeTurnsPrint {

    public static class TakeTurns {

        private static boolean flag = true;

        private static int count = 0;

        public synchronized void print1() {
            for (int i = 1; i <= 50; i++) {
                while (!flag) {
                    try {
                        System.out.println("print1: wait before");
                        wait();
                        System.out.println("print1: wait after");
                    } catch (InterruptedException e) {
                    }
                }

                System.out.println("print1: " + ++count);
                flag = !flag;
                notifyAll();
            }
        }

        public synchronized void print2() {
            for (int i = 1; i <= 50; i++) {
                while (flag) {
                    try {
                        System.out.println("print2: wait before");
                        wait();
                        System.out.println("print2: wait after");
                    } catch (InterruptedException e) {
                    }
                }

                System.out.println("print2: " + ++count);
                flag = !flag;
                notifyAll();
            }
        }
    }

    public static void main(String[] args){

        TakeTurns takeTurns = new TakeTurns();

        new Thread(new Runnable() {
            @Override
            public void run() {
                takeTurns.print1();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                takeTurns.print2();
            }
        }).start();

    }

}


3. 写两个线程,一个线程打印1~ 52,另一个线程打印A~Z,打印顺序是12A34B…5152Z

package com.example.javatest.theardTest.MultiThreadAlgorithm;

/**
 * 两线程,一个打印数字从1到52,另一个打印字母从A到Z,输出:12A34B56C...5152Z
 */
public class TakeTurnsPrint2 {
    private boolean flag;
    private int count;

    public synchronized void printNum() {
        for (int i = 0; i < 26; i++) {
                while (flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                flag = !flag;
                System.out.print(++count);
                System.out.print(++count);
                notify();
        }
    }

    public synchronized void printLetter() {
        for (int i = 0; i < 26; i++) {
                while (!flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                flag = !flag;
                System.out.print((char) (65 + i));
                notify();
        }
    }

    public static void main(String[] args) {

        TakeTurnsPrint2 turnsPrint2 = new TakeTurnsPrint2();

        new Thread(new Runnable() {
            @Override
            public void run() {
                turnsPrint2.printNum();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                turnsPrint2.printLetter();
            }
        }).start();
    }
}

4. 编写一个程序,启动三个线程,三个线程的ID分别是A,B,C;,每个线程将自己的ID值在屏幕上打印5遍,打印顺序是ABCABC…

package com.example.javatest.theardTest.MultiThreadAlgorithm;

/**
 * 编写一个程序,启动三个线程,三个线程的ID分别是A,B,C;,每个线程将自己的ID值在屏幕上打印5遍,打印顺序是ABCABC...
 */
public class ABCABCABC {

    private int flag = 0;

    public synchronized void printA() {
        for(int i = 0; i < 5; i++) {
            while (flag != 0) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            flag = 1;
            System.out.print("A");
            notifyAll();
        }
    }

    public synchronized void printB() {
        for(int i = 0; i < 5; i++) {
            while (flag != 1) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            flag = 2;
            System.out.print("B");
            notifyAll();
        }
    }

    public synchronized void printC() {
        for(int i = 0; i < 5; i++) {
            while (flag != 2) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            flag = 0;
            System.out.print("C");
            notifyAll();
        }
    }

    public static void main(String[] args) {

        ABCABCABC abcabcabc = new ABCABCABC();

        new Thread(new Runnable() {
            @Override
            public void run() {
                abcabcabc.printA();
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                abcabcabc.printB();
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                abcabcabc.printC();
            }
        }).start();
    }
}


5. 编写10个线程,第一个线程从1加到10,第二个线程从11加20…第十个线程从91加到100,最后再把10个线程结果相加。

/**
 * 编写10个线程,第一个线程从1加到10,第二个线程从11加20…第十个线程从91加到100,最后再把10个线程结果相加
 */
public class TenThreadSum {

    public static class SumThread extends Thread{

        int forct = 0;  int sum = 0;

        SumThread(int forct){
            this.forct = forct;
        }

        @Override
        public void run() {
            for(int i = 1; i <= 10; i++){
                sum += i + forct * 10;
            }
            System.out.println(getName() + "  " + sum);
        }
    }

    public static void main(String[] args) {

        int result = 0;

        for(int i = 0; i < 10; i++){
            SumThread sumThread = new SumThread(i);
            sumThread.start();
            try {
                sumThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            result = result + sumThread.sum;
        }
        System.out.println("result   " + result);
    }
}

6. 三个窗口同时卖票

/**
 * 三个窗口同时卖票
 */

/**
 * 票
 */
class Ticket {
    private int count = 1;
    public void sale() {
        while (true) {
            synchronized (this) {
                if (count > 200) {
                    System.out.println("票已经卖完啦");
                    break;
                } else {
                    System.out.println(Thread.currentThread().getName() + "卖的第 " + count++ + " 张票");
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

/**
 * 售票窗口
 */
class SaleWindows extends Thread {
    
    private Ticket ticket;

    public SaleWindows(String name, Ticket ticket) {
        super(name);
        this.ticket = ticket;
    }

    @Override
    public void run() {
        super.run();
        ticket.sale();
    }
}

public class TicketDemo {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        SaleWindows windows1 = new SaleWindows("窗口1", ticket);
        SaleWindows windows2 = new SaleWindows("窗口2", ticket);
        SaleWindows windows3 = new SaleWindows("窗口3", ticket);

        windows1.start();
        windows2.start();
        windows3.start();
    }
}



7. 生产者消费者

7.1 synchronized方式


public class FruitPlateDemo {

    private final static String LOCK = "lock";

    private int count = 0;

    private static final int FULL = 10;

    public static void main(String[] args) {

        FruitPlateDemo fruitDemo1 = new FruitPlateDemo();

        for (int i = 1; i <= 5; i++) {
            new Thread(fruitDemo1.new Producer(), "生产者-" + i).start();
            new Thread(fruitDemo1.new Consumer(), "消费者-" + i).start();
        }
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                synchronized (LOCK) {
                    while (count == FULL) {
                        try {
                            LOCK.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    System.out.println("生产者 " + Thread.currentThread().getName() + " 总共有 " + ++count + " 个资源");
                    LOCK.notifyAll();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                synchronized (LOCK) {
                    while (count == 0) {
                        try {
                            LOCK.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("消费者 " + Thread.currentThread().getName() + " 总共有 " + --count + " 个资源");
                    LOCK.notifyAll();
                }
            }
        }
    }
}

7.2 ReentrantLock方式 (可以保证顺序)

public class Demo1 {

    private int count = 0;

    private final static int FULL = 10;

    private Lock lock;

    private Condition notEmptyCondition;

    private Condition notFullCondition;

    {
        lock = new ReentrantLock();
        notEmptyCondition = lock.newCondition();
        notFullCondition = lock.newCondition();

    }

    class Producer implements Runnable {

        @Override
        public void run() {

            for (int i = 0; i < 10; i++) {
                lock.lock();
                try {
                    while(count == FULL) {
                        try {
                            notFullCondition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("生产者 " + Thread.currentThread().getName() + " 总共有 " + ++count + " 个资源");
                    notEmptyCondition.signal();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                lock.lock();
                try {
                    while(count == 0) {
                        try {
                            notEmptyCondition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("消费者 " + Thread.currentThread().getName() + " 总共有 " + --count + " 个资源");
                    notFullCondition.signal();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    public static void main(String[] args) {
        Demo1 demo1 = new Demo1();
        for (int i = 1; i <= 5; i++) {
            new Thread(demo1.new Producer(), "生产者-" + i).start();
            new Thread(demo1.new Consumer(), "消费者-" + i).start();
        }
    }
}

7.3 BlockingQueue方式

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Demo2 {

    private int count = 0;

    private BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

    public static void main(String[] args) {

        Demo2 demo2 = new Demo2();
        for (int i = 1; i <= 5; i++) {
            new Thread(demo2.new Producer(), "生产者-" + i).start();
            new Thread(demo2.new Consumer(), "消费者-" + i).start();
        }
    }

    class Producer implements Runnable {

        @Override
        public void run() {

            for (int i = 0; i < 10; i++) {
                try {
                    queue.put(1);
                    System.out.println("生产者 " + Thread.currentThread().getName() + " 总共有 " + ++count + " 个资源");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Consumer implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    queue.take();
                    System.out.println("消费者 " + Thread.currentThread().getName() + " 总共有 " + --count + " 个资源");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

8. 交替打印两个数组

package com.example.javatest.theardTest.MultiThreadAlgorithm;

public class TwoArr {

    int[] arr1 = new int[]{1, 3, 5, 7, 9};
    int[] arr2 = new int[]{2, 4, 6, 8, 10};

    boolean flag;

    public synchronized void print1(){
        for(int i= 0; i < arr1.length; i++){
            while (flag){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            flag = !flag;
            System.out.println(arr1[i]);
            notifyAll();
        }
    }

    public synchronized void print2(){
        for(int i= 0; i < arr2.length; i++){
            while (!flag){
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            flag = !flag;
            System.out.println(arr2[i]);
            notifyAll();
        }
    }

    public static void main(String[] args) {

        TwoArr twoArr = new TwoArr();

        new Thread(new Runnable() {
            @Override
            public void run() {
                twoArr.print1();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                twoArr.print2();
            }
        }).start();
    }

}


9. 使用多线程,模拟龟兔赛跑的场景。

//模拟龟兔百米赛跑

public class ThreadTest1 extends Thread{

    @Override
    public void run() {
        try {
            pao();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void pao() throws InterruptedException {
        for(int i=1;i<=10;i++) {
            System.out.println(Thread.currentThread().getName()+"打卡:"+i+"米");
            Thread.sleep(1000);
        }
    }

}

public class ThreadTest2 {

    public static void main(String[] args) {
        Thread th1=new ThreadTest1();
        Thread th2=new ThreadTest1();

        th1.setName("龟");
        th2.setName("兔");

        th1.start();
        th2.start();
    }
}

10. 编写一个有两个线程的程序,第一个线程用来计算2~100000之间的素数的个数,第二个线程用来计算100000~200000之间的素数的个数,最后输出结果。

//线程类,以及判断素数的方法
public class ThreadTest3 implements Runnable {

    @Override
    public void run() {
        int a=fun1();
        System.out.println("一素数个数:"+a);
    }

    private static int fun1() {

        int sum = 0;// 素数个数

        for (int i = 2; i <= 100000; i++) {// 某个数
            int j=2;
            while(i%j!=0) {
                j++;
            }
            if(j==i) {
                sum++;
            }

        }

        return sum;
    }

}
public class ThreadTest5 implements Runnable{

    @Override
    public void run() {
        int a=fun2();
        System.out.println("二素数个数:"+a);
    }

    private static int fun2() {

        int sum = 0;// 素数个数

        for (int i = 100000; i <= 200000; i++) {// 某个数
            int j=2;
            while(i%j!=0) {
                j++;
            }
            if(j==i) {
                sum++;
            }

        }

        return sum;
    }

}
public class ThreadTest4 {
    public static void main(String[] args) {
        ThreadTest3 th=new ThreadTest3();
        Thread th1=new Thread(th);
        th1.start();

        ThreadTest5 th2=new ThreadTest5();
        Thread th3=new Thread(th2);
        th3.start();
    }

}

11. 使用多线程实现多个文件同步复制功能,并在控制台显示复制的进度,进度以百分比表示。例如:把文件A复制到E盘某文件夹下,在控制台上显示“XXX文件已复制10%”,“XXX文件已复制20%”……“XXX文件已复制100%”,“XXX复制完成!”

//重点:java.text.DecimalFormat的使用(格式化十进制数)

package two;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.text.DecimalFormat;

public class CopyFile extends Thread{

    public File older;//源文件路径
    public File newer;//目标文件路径

    //构造函数把路径封装成文件
    public CopyFile(String older, String newer) {
        this.older = new File(older);
        this.newer = new File(newer);
    }

    @Override
    public void run() {
        FileInputStream fis=null;
        FileOutputStream fos=null;

        try {
            fis=new FileInputStream(older);
            fos=new FileOutputStream(newer);

            long len=older.length();//获取源文件的长度    跟  fis.available()的结果


            //文件大小的十分之一
            byte[] b=new byte[(int) (older.length()/10)];//声明一个字节数组,每次读取的数据存到这里
            int length=0;//返回每次读取的数据长度


            System.out.println(len);
            double temp=0;

            DecimalFormat df=new DecimalFormat("##%");

            //最多将b.length个字节读入一个byte数组中,也就是每次读1/10个字节,然后循环,直到读到问价尾
            while((length = fis.read(b)) !=-1) {//读到文件尾会返回-1
                fos.write(b, 0, length);//把每次读取的内容,输出到目标路径文件中
                temp +=length;//把每次读取的数据长度累加
                double d=temp/len;//计算出已经读取的长度占文件总长度的比率

                int jd=(int) d;
                if(jd%10==0) {
                    System.out.println(older.getName()+"文件复制了:"+df.format(d));//将小数给格式化
                }
                System.out.println(older.getName()+"文件已复制了:"+d);
            }
            System.out.println(older.getName()+"复制完毕!");

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                fis.close();
                fos.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}

package two;

public class CopyTest {

    public static void main(String[] args) {
        //两个线程实例
        CopyFile cf1=new CopyFile("G://金泰妍.MP3", "F://金泰妍.MP3");
        CopyFile cf2=new CopyFile("G://GD.MP3", "F://GD.MP3");
        cf1.start();
        cf2.start();
    }
}

12. 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。考虑到线程的安全性写出程序。

package test.one;

//4、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。考虑到线程的安全性写出程序。
//使线程同步
public class Test1 {//一个主线程

    private int j;//变量j

    public static void main(String[] args) {
        Test1 t=new Test1();
        Add add=t.new Add();//内部类的实例
        Sub sub=t.new Sub();

        for(int i=0;i<2;i++){//循环两边创建四个线程,两加两减
            Thread t1=new Thread(add);
            t1.start();
            Thread t2=new Thread(sub);
            t2.start();
        }


    }

    //考虑线程安全的问题,为方法加synchronized关键字,保证一时间只有一个线程操作该方法
    private synchronized void add(){
        j++;
        System.out.println(Thread.currentThread().getName()+":"+j);
    }

    private synchronized void sub(){
        j--;
        System.out.println(Thread.currentThread().getName()+":"+j);
    }

    class Add implements Runnable{//线程,成员内部类无条件访问外部类的所有成员

        //线程调用了j+的方法
        @Override
        public void run() {
            for (int i=0;i<10;i++){
                add();
            }
        }
    }

    class Sub implements Runnable{//线程,同上

        //线程调用了j-的方法
        @Override
        public void run() {
            for (int i=0;i<10;i++){
                sub();
            }
        }
    }
}
posted @ 2022-11-28 17:04  starmoon1900  阅读(1807)  评论(0编辑  收藏  举报