java--threads--a collection of exercises

An advantage of anonymous classes is that they can easily access external local variables.
The premise is that external local variables need to be declared final. (Not needed after JDK7)

======================

Synchronization Method 1: Normal

Synchronization method 2: write keywords in object methods, use this

Synchronization method 3: Add the modifier synchronized before the method, the effect is the same as method 2

==================

Topic 1--Find file contents synchronously

Change the exercise-find file content to multi-threading to find the file content
. The idea of ​​the original exercise is to traverse all files. When the file is .java, search for the content of this file. After the search is complete, traverse the next file.

Now adjust this idea through multi-threading:
traverse all files, when the file is .java, create a thread to find the content of the file, don't wait for the thread to end, continue to traverse the next file

package zsc.czy.zhonghe;

import java.io.File;
import java.io.FileReader;

public class findContent {

    public static void main(String[] args) {
        File f = new File("d:/test");
        
        search(f, "Hello");
    }

    public static void search(File f, String search) {
        System.out.println(f); //d:\find.txt
        System.out.println(f.getAbsolutePath());
//      System.out.println(f.getName());//find.txt
        if (f.isFile()) {
            if (f.getName().toLowerCase().endsWith(".java")) {
                new Thread(new Runnable() {
                    
                    @Override
                    public void run() {
                        String fileContent = readFileConent(f);
                        if (fileContent.contains(search)) {
                            System.out.printf("找到子目标字符串%s,在文件:%s%n", search, f);
                        }
                    }
                }).start();
                
            }
        }
        if(f.isDirectory()){
            File[] fs = f.listFiles();
            for(File file :fs){
                search(file,search);
            }
        }

    }

    private static String readFileConent(File f) {
        try (FileReader fr = new FileReader(f);) {
            char[] c = new char[(int) f.length()];
            fr.read(c);
            String s = new String(c);
            return s;

        } catch (Exception e) {
            return null;
        }

    }
}

Topic 2 - Hero Charge

Heroes can have a skill called: Wave Fist-a du gen.
Every second, you can send it once, but only 3 times in a row.

After sending 3 times, it needs to be charged for 5 seconds, fully charged, and then continue to send.

package zsc.czy.thread;

public class Hero {
    String name;
    int hp;
    int damage;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }

    public int getDamage() {
        return damage;
    }

    public void setDamage(int damage) {
        this.damage = damage;
    }

    public boolean isDead() {
        return 0 >= hp ? true : false;
    }

    public void attackHero(Hero h) {
        try {
            // 为了表示攻击需要时间,每次攻击暂停1000毫秒
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        h.hp -= damage;
        System.out.format("%s 正在攻击 %s,%s的血编程了 %.0f%n", name, h.name, h.name,
                h.hp);
        if (h.isDead()) {
            System.out.println(h.name + "死了");
        }
    }

    int totalTime = 3;

    public void adugen() {
        while (true) {
            for (int i = 0; i < totalTime; i++) {
                System.out.printf("波动拳第%d发%n", i + 1);
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
            System.out.println("开始为时5秒的充能");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {

                e.printStackTrace();
            }

        }
    }

    public static void main(String[] args) {
        Hero h = new Hero();
        h.name = "红仔";
        h.adugen();
    }
}

Topic 3--Crack the password

  1. Generate a random string of length 3 and use this string as the password

  2. Create a cracking thread, using the exhaustive method, to match this password

  3. Create a log thread and print which strings have been used to match. This log thread is designed as a daemon thread

Tip: The cracking thread puts the possible passwords generated by the exhaustive method in a container, and the log thread continuously takes out the possible passwords from this container and prints them out. If the container is found to be empty, take a rest for 1 second. If it is found that it is not empty, it will keep taking it out and print it.

==============================

HashMap is not strictly allowed to store null -- not thread-safe class
Hashtable strictly

ArrayList is not thread safe
Vector is thread safe class

====================

Topic 4 - Thread-safe MyStack

Another way to complete the exercise by converting a non-thread-safe collection to thread-safe - a thread-safe MyStack

Topic 5--Deadlock

3 synchronization objects a, b, c
3 threads t1, t2, t3

Deliberately design the scenario such that these 3 threads deadlock each other

//我这样设计是不成功的
package zsc.czy.thread;

public class SiSuo {
    public static void main(String[] args) {
        final Hero ahri = new Hero();
        ahri.name = "九尾妖狐";
        final Hero annie = new Hero();
        annie.name = "安妮";
        final Hero leqing = new Hero();
        annie.name = "李青";

        Thread t1 = new Thread() {
            public void run() {
                // 占有九尾妖狐
                synchronized (ahri) {
                    System.out.println("t1 已占有九尾妖狐");
                    try {
                        // 停顿1000毫秒,另一个线程有足够的时间占有安妮
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    System.out.println("t1 试图占有安妮");
                    System.out.println("t1 等待中 。。。。");
                    synchronized (annie) {
                        System.out.println("do something");
                    }
                }

            }
        };
        t1.start();
        Thread t2 = new Thread() {
            public void run() {
                // 占有安妮
                synchronized (annie) {
                    System.out.println("t2 已占有安妮");
                    try {

                        // 停顿1000秒,另一个线程有足够的时间占有暂用九尾妖狐
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println("t2 试图占有李青");
                    System.out.println("t2 等待中 。。。。");
                    synchronized (leqing) {
                        System.out.println("do something");
                    }
                }

            }
        };
        t2.start();
        
        Thread t3 = new Thread(){
            public void run() {
                synchronized (leqing) {
                    System.out.println("t3已占有李青");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        
                        e.printStackTrace();
                    }
                    System.out.println("t3 试图占有九尾妖狐");
                    System.out.println("t3 等待中 。。。。");
                }
                synchronized (ahri) {
                    System.out.println("do something");
                }
                
            };
        };
        t3.start();
    }
}

The correct way is:

package multiplethread;
 
public class TestThread {
       
    public static void main(String[] args) {
        Object a = new Object();
        Object b = new Object();
        Object c = new Object();
 
        Thread t1 =new Thread(){
            public void run(){
                synchronized (a) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    synchronized (b) {
                        synchronized (c) {
                             
                        }
                    }
                }  
            }
        };
        Thread t2 =new Thread(){
            public void run(){
                synchronized (c) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    synchronized (a) {
                        synchronized (b) {
                             
                        }
                    }
                }  
            }
        };
        Thread t3 =new Thread(){
            public void run(){
                synchronized (b) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    synchronized (c) {
                        synchronized (a) {
                             
                        }
                    }
                }  
            }
        };
 
        t1.start();
        t2.start();
        t3.start();
        
   }
         
}

================

Thread interaction using wait and notify

this.wait() means to let the thread holding this wait, and temporarily release the thread holding
this.notify() means to notify those threads waiting on this that they can wake up.

public synchronized void recover() {
        hp = hp + 1;
         System.out.printf("%s 回血1点,增加血后,%s的血量是%.0f%n", name, name, hp);
        // 通知那些等待在this对象上的线程,可以醒过来了,如第20行,等待着的减血线程,苏醒过来
        this.notify();
    }

    // 掉血  同步方式和上面效果一样 这个方式
    public void hurt() {
        synchronized (this) {
            if (hp == 1) {
                // 让占有this的减血线程,暂时释放对this的占有,并等待
                try {
                    this.wait();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }
            hp = hp - 1;
            System.out.printf("%s 减血1点,减少血后,%s的血量是%.0f%n", name, name, hp);

        }
    }

Don't forget that Thread's parent class is also Object

Topic--Thread Interaction

Assuming the HP thread runs more frequently, the hero's max HP is 1000

Design the interaction between the blood adding thread and the blood reducing thread, so that after the blood return is full, the blood adding thread waits until there is a blood reducing thread to reduce blood

    // 回血
    public synchronized void recover() {
        
        if(hp>=1000){
            try {
                this.wait(); //后加的
            } catch (InterruptedException e) {
                
                e.printStackTrace();
            }
        }
        
        hp = hp + 1;
        System.out.printf("%s 回血1点,增加血后,%s的血量是%.0f%n", name, name, hp);
        // 通知那些等待在this对象上的线程,可以醒过来了,如第73行,等待着的减血线程,苏醒过来
        this.notify(); 
    }

    // 掉血  同步方式和上面效果一样 这个方式
    public void hurt() {
        synchronized (this) {
            if (hp == 1) {
                // 让占有this的减血线程,暂时释放对this的占有,并等待
                try {
                    this.wait();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }
            hp = hp - 1;
            System.out.printf("%s 减血1点,减少血后,%s的血量是%.0f%n", name, name, hp);
            
            //notify() 的意思是,通知一个等待在这个同步对象上的线程,你可以苏醒过来了,有机会重新占用当前对象了。
            //掉血之后,唤醒等待的线程
            this.notify();//后加的
        }
    }

Topic--Multi-threaded interaction

On the basis of the above exercise, increase the blood return thread to 2, reduce the blood thread to 5, and run at the same time.

Run for a period of time, observe errors that will occur, analyze the causes of errors, and consider solutions

Topic--Producer Consumer Problem

The producer-consumer problem is a very typical thread interaction problem.

  1. Use the stack to store data
    1.1 Transform the stack to support thread safety
    1.2 Process the boundary operations of the stack. When the data in the stack is 0, the thread accessing the pull will wait. When the data in the stack is 200, the thread accessing the push will wait
  2. Provide a producer (Producer) thread class that produces random uppercase characters and pushes them onto the stack
  3. Provides a Consumer thread class that pops characters from the stack and prints to the console
  4. Provide a test class to run two producer and three consumer threads concurrently, with results similar to the following:

==================

Lock

topic

In the Exercise - Thread-Safe MyStack exercise, use synchronized to modify MyStack to be a thread-safe class.

Next, use Lock to modify MyStack to be a thread-safe class

Remove synchronized ,
use lock to occupy the lock ,
use unlock to release the lock
, it must be executed in finally, in case heroes.addLast throws an exception, it will also be executed

package multiplethread;
    
import java.util.LinkedList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
import charactor.Hero;
    
public class MyStack {
    
    LinkedList<Hero> heros = new LinkedList<Hero>();
 
    Lock lock = new ReentrantLock();
     
    //把synchronized去掉
    public  void push(Hero h) {
        try{
            //使用lock占用锁
            lock.lock();
            heros.addLast(h);          
        }
        finally{
            //使用unlock释放锁
            //必须放在finally执行,万一heros.addLast抛出异常也会执行
            lock.unlock();
        }
     
    }
    
    //把synchronized去掉
    public  Hero pull() {
        try{
            //使用lock占用锁
            lock.lock();
            return heros.removeLast();         
        }
        finally{
            //使用unlock释放锁
            //必须放在finally执行,万一heros.removeLast();抛出异常也会执行          
            lock.unlock();
        }
    }
    
    public Hero peek() {
        return heros.getLast();
    }
        
    public static void main(String[] args) {
 
    }
    
}

Topic -- use tryLock to solve the deadlock problem

When multiple threads occupy multiple synchronization objects in different orders, deadlock may occur.

Deadlock occurs because if synchronized does not occupy the synchronization object, it will wait for a long time. With the limited waiting time of tryLock, the deadlock problem is solved.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325388656&siteId=291194637