首页 > 编程语言 >java 使用多线程的注意事项

java 使用多线程的注意事项

时间:2023-08-30 23:31:30浏览次数:32  
标签:java Thread int void 线程 注意事项 new 多线程 public


线程安全:

确保共享资源的正确访问和修改,避免并发冲突。可以通过同步机制(如锁、互斥量、信号量等)或使用线程安全的数据结构来实现线程安全。

案例:银行账户并发访问

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class BankAccount {
    private int balance;
    private Lock lock = new ReentrantLock();

    public void deposit(int amount) {
        lock.lock();
        try {
            balance += amount;
        } finally {
            lock.unlock();
        }
    }

    public void withdraw(int amount) {
        lock.lock();
        try {
            balance -= amount;
        } finally {
            lock.unlock();
        }
    }

    public int getBalance() {
        return balance;
    }
}

避免死锁:

死锁是指两个或多个线程无限期地等待对方持有的资源,导致程序无法继续执行。为避免死锁,要谨慎设计锁的获取顺序,并尽量避免嵌套锁的使用。另外,可以使用工具来检测和分析死锁问题。

案例:死锁避免

class ResourceA {
    public synchronized void methodA(ResourceB resourceB) {
        // 获取资源A的锁
        System.out.println("methodA获取了ResourceA的锁");
        try {
            Thread.sleep(100);
            // 尝试获取资源B的锁
            resourceB.methodB();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void methodC() {
        // 获取资源A的锁
        System.out.println("methodC获取了ResourceA的锁");
    }
}

class ResourceB {
    public synchronized void methodB() {
        // 获取资源B的锁
        System.out.println("methodB获取了ResourceB的锁");
    }

    public synchronized void methodD(ResourceA resourceA) {
        // 获取资源B的锁
        System.out.println("methodD获取了ResourceB的锁");
        try {
            Thread.sleep(100);
            // 尝试获取资源A的锁
            resourceA.methodC();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class DeadlockAvoidanceExample {
    public static void main(String[] args) {
        ResourceA resourceA = new ResourceA();
        ResourceB resourceB = new ResourceB();
        Thread thread1 = new Thread(() -> resourceA.methodA(resourceB));
        Thread thread2 = new Thread(() -> resourceB.methodD(resourceA));
        thread1.start();
        thread2.start();
    }
}


避免竞态条件:

竞态条件是指多个线程在访问和修改共享资源时出现的不确定性结果。要避免竞态条件,可以使用同步机制、原子操作、线程安全的类等。

案例:线程安全的计数器

import java.util.concurrent.atomic.AtomicInteger;

class Counter {
    private AtomicInteger count = new AtomicInteger(0);

    public int incrementAndGet() {
        return count.incrementAndGet();
    }

    public int getCount() {
        return count.get();
    }
}

public class ThreadSafeCounterExample {
    public static void main(String[] args) {
        Counter counter = new Counter();
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.incrementAndGet();
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);
        thread1.start();
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Count: " + counter.getCount());
    }
}

避免线程间通信问题:

当多个线程共享数据时,必须正确地进行线程间通信,以保证数据的一致性和正确性。可以使用管道、消息队列、锁、条件变量等机制来实现线程间的通信。

案例:生产者-消费者模型

import java.util.LinkedList;
import java.util.Queue;

class ProducerConsumer {
    private Queue<Integer> queue = new LinkedList<>();
    private final int MAX_SIZE = 10;

    public void produce() throws InterruptedException {
        synchronized (this) {
            while (queue.size() >= MAX_SIZE) {
                wait();
            }

            int item = (int) (Math.random() * 100);
            queue.add(item);
            System.out.println("Produced: " + item);

            notifyAll();
        }
    }

    public void consume() throws InterruptedException {
        synchronized (this) {
            while (queue.isEmpty()) {
                wait();
            }

            int item = queue.remove();
            System.out.println("Consumed: " + item);

            notifyAll();
        }
    }
}

public class ProducerConsumerExample {
    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();

        Runnable producerTask = () -> {
            try {
                while (true) {
                    pc.produce();
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Runnable consumerTask = () -> {
            try {
                while (true) {
                    pc.consume();
                    Thread.sleep(2000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };

        Thread producerThread = new Thread(producerTask);
        Thread consumerThread = new Thread(consumerTask);

        producerThread.start();
        consumerThread.start();
    }
}

控制线程数量:

合理控制线程数量,防止线程过多导致系统资源耗尽或线程调度开销过大。可以使用线程池来管理和调度线程,以提高效率和灵活性。

案例:控制线程池大小

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10; i++) {
            Runnable task = () -> {
                System.out.println("Task executed by: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            executor.submit(task);
        }

        executor.shutdown();
    }
}

错误处理:

在多线程程序中,及时捕获和处理线程抛出的异常很重要,否则可能导致整个应用程序崩溃。可以使用try-catch块或Thread.UncaughtExceptionHandler来处理异常。

案例:异常处理

class ExceptionHandlingThread implements Runnable {
    @Override
    public void run() {
        try {
            int result = 10 / 0; // 抛出算术异常
            System.out.println("Result: " + result);
        } catch (ArithmeticException e) {
            System.out.println("Caught exception: " + e.getMessage());
        }
    }
}

public class ExceptionHandlingExample {
    public static void main(String[] args) {
        Thread thread = new Thread(new ExceptionHandlingThread());
        thread.start();
    }
}

避免长时间阻塞:

在多线程编程中,应尽量避免长时间的阻塞操作,如长时间的IO操作或等待其他线程的锁释放。可以使用非阻塞IO、异步操作或超时机制来避免线程长时间阻塞。

案例:避免线程长时间阻塞

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class NonBlockingServerExample {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);

        while (true) {
            Socket socket = serverSocket.accept();

            // 创建新的线程处理客户端请求
            Thread thread = new Thread(() -> {
                try {
                    // 处理socket的输入和输出
                    System.out.println("Processing request from client");
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });

            thread.start();
        }
    }
}

资源管理:

在多线程环境下,要注意正确管理和释放资源,防止资源泄漏或过度占用资源。

案例:多线程资源管理

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

class ConnectionPool {
    private static final int MAX_CONNECTIONS = 10;
    private static final String DB_URL = "jdbc:mysql://localhost:3306/db";
    private static final String USER = "root";
    private static final String PASSWORD = "password";
    private static Connection[] connections = new Connection[MAX_CONNECTIONS];
    private static boolean[] isConnectionFree = new boolean[MAX_CONNECTIONS];

    static {
        for (int i = 0; i < MAX_CONNECTIONS; i++) {
            try {
                connections[i] = DriverManager.getConnection(DB_URL, USER, PASSWORD);
                isConnectionFree[i] = true;
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized Connection getConnection() {
        while (true) {
            for (int i = 0; i < MAX_CONNECTIONS; i++) {
                if (isConnectionFree[i]) {
                    isConnectionFree[i] = false;
                    return connections[i];
                }
            }

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

    public synchronized void releaseConnection(Connection connection) {
        for (int i = 0; i < MAX_CONNECTIONS; i++) {
            if (connections[i] == connection) {
                isConnectionFree[i] = true;
                break;
            }
        }

        notifyAll();
    }
}

public class ConnectionPoolingExample {
    public static void main(String[] args) {
        ConnectionPool connectionPool = new ConnectionPool();

        Runnable task = () -> {
            Connection connection = connectionPool.getConnection();
            System.out.println("Got connection: " + connection);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                connectionPool.releaseConnection(connection);
                System.out.println("Released connection: " + connection);
            }
        };

        for (int i = 0; i < 20; i++) {
            new Thread(task).start();
        }
    }
}

监控和调试:

在开发和部署多线程应用程序时,要进行充分的监控和调试,及时发现和解决潜在的问题。可以使用工具和框架来帮助监控线程状态、调试并发问题等。

案例:监控和调试

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MonitoringAndDebuggingExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10; i++) {
            Runnable task = () -> {
                System.out.println("Task executed by: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            executor.submit(task);
        }

        executor.shutdown();
    }
}

测试和验证:

针对多线程应用程序,要进行充分的测试和验证,包括并发测试、压力测试、性能测试等,以确保程序的正确性和稳定性。

案例:并发测试和性能测试

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ConcurrencyAndPerformanceTestingExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 100; i++) {
            Runnable task = () -> {
                System.out.println("Task executed by: " + Thread.currentThread().getName());
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            executor.submit(task);
        }

        executor.shutdown();
    }
}

标签:java,Thread,int,void,线程,注意事项,new,多线程,public
From: https://blog.51cto.com/AmbitionGarden/7298389

相关文章

  • 更换固态硬盘注意事项
     更换固态硬盘前,如果现有插口“已经存在固态硬盘”,那么切记,一定不要直接更换,一定要先把“已经存在固态硬盘”拔下来,然后不要插任何硬盘,然后重启系统(或者关机再开机更好),这样是为了让主板把已经存在固态硬盘的插口重置,如果不这样操作,直接更换固态硬盘,可能会存在之前固态硬盘的缓......
  • 多线程执行工具方法
    publicstatic<P,T>List<CompletableFuture<T>>multiThreadRun(Function<P,T>run,Collection<P>list,intthreadSize,Executorexecutor,booleanwaitRunFinal){List<CompletableFuture<T>>cf=newArr......
  • Java中的ThreadLocal详解
     一、ThreadLocal简介多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal是除了加锁这种同步方式之外的一种保证一种规避多线......
  • 1-JAVA-面向对象程序设计概论-笔记整理
    学习之路,长路漫漫,写学习笔记的过程就是把知识讲给自己听的过程。这个过程中,我们去记录思考的过程,便于日后复习,梳理自己的思路。学习之乐,独乐乐,不如众乐乐,把知识讲给更多的人JAVA-面向对象程序设计概论-笔记整理内容提要结构化程序设计方法面向对象技术及UML简介面向对象基本概念面......
  • java练习:使用Stream
    packagecom.example.ss_0203_array.test.test_0830;importjava.util.ArrayList;importjava.util.Collections;importjava.util.stream.Stream;publicclasstest3{publicstaticvoidmain(String[]args){/***按照下面的要求完成集合的创......
  • java directoryAndfileHide
    javaimportjava.io.File;importjava.util.Scanner;importjava.io.IOException;importjava.nio.file.Files;importjava.nio.file.attribute.DosFileAttributeView;importjava.nio.file.attribute.DosFileAttributes;publicclassDirectoryandFileHIde{pub......
  • Java8知识梳理
    Java8的改进速度更快代码更少(Lambda表达式)引入强大的StreamAPI便于并行最大化减少空指针异常(Optional)Nashorn引擎,允许在JVM上运行js应用并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。相比较串行的流,并行的流可以很大程度上提高程序的执行......
  • JavaNote-变量与运算符
    1.关键字(keyword)定义:被Java语言赋予了特殊含义,用做专门用途的字符串(或单词)称为关键字。特点:全部关键字都是小写字母。官方地址:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html类型关键字用于定义数据类型的关键字class、interface、......
  • 03-JavaScript
    变量:变量的声明和赋值:使用var、let或const关键字声明变量,并赋予其一个值。基本数据类型:布尔值、数字、字符串、undefined、null等基本数据类型的概念和使用。类型的转换:数据类型之间的转换,包括显式转换和隐式转换。运算符:算术运算符、比较运算符、逻辑运算符、赋值......
  • python多线程
    python多线程多线程threading,利用CPU和IO可以同时执行的原理多进程multiprocessing,利用多核CPU的能力,真正的并行执行任务异步IOasyncio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行使用Lock对资源加锁,防止冲突访问使用Queue实现不同线程/进程之间的数据通信,实现生......