Java多线程

Posted 我想回家

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多线程相关的知识,希望对你有一定的参考价值。

多线程和多进程的区别:

  本质的区别在于每隔进程拥有自己的一整套变量,而线程则共享数据.在有些操作系统中,与进程相比较,线程更轻量级,创建,撤销一个线程比启动新进程的开销要小的多.\

  简单的来说:一个进程至少有一个线程,线程是进程的组成部分,线程结束,进程不一定结束,进程结束,线程一定结束.

为什么要使用线程?

  使用线程是为了给其他任务提供运行的机会.在普通的程序中,只能顺序执行每一个任务,使用线程可以在一个任务未完成时执行其他的任务,

如何实现线程?

  [1].继承Thread类或者实现Runnable接口.

  [2].重写run方法.

  [3].调用run方法(切记使用 对象.start()(来启动新的线程) 来调用,不能直接调用run方法).

  在继承Thread类和实现Runnable接口的调用run方法也是不同的,前者直接是对象.start()(new 对象().start()),后者是利用Thread类的对象来调用start的方法(也就是new Thread(new 对象()).start()).

线程的状态:

  New(新创建),Runnable(可运行),Blocked(被阻塞),Waiting(等待),Timed waiting(计时等待),Terminated(被终止),

  新创建是指使用new操作符创建一个新线程,还没有运行.

  可运行是指调用了start的方法,处于Runnable状态,这个线程可能正在运行,也可能没在运行,这取决于操作系统给线程提供运行的时间.

  当一个线程试图获取一个内部的对象锁,而该锁被其它线程持有,则该线程进入阻塞状态,直到线程调度器允许该线程持有这个对象锁的时候.

  当线程等待另一个线程通知调度器一个条件时,他自己进入等待状态.简单的来说等待另一个线程释放他所需要的资源的过程.

  Thread.sleep,Object.wait,Thread.join,Lock.tryLock以及Condition.await是带有超时参数的方法,调用他们将导致线程进入计时等待.

  被终止的线程:(1).由于run方法的正常退出而自然死亡,(2).因为一个没有捕获的异常终止了run方法而意外死亡.

  获取线程的状态:对象.getState().

线程的属性:

  [1].优先级(1~10):MIN_PRIORITY(1),MAX_PRIORITY(10),NORM_PRIORITY(5).线程的优先级是高度依赖于系统的,线程调度器有机会选择新线程的时候,首先选择具有较高优先级的线程.

  [2].守护线程:t.setDaemon(true)将一个线程转化为守护线程(必须在线程启动前调用),守护线程的唯一用途是为其他线程提供服务的.

  [3].未捕获异常处理器(暂时不懂,以后懂了再补充).

线程是为了给其他线程运行的机会,这样的话程序有可能需要同步,那么同步就会带来读脏数据的问题,也就是共享数据的问题,这提供两种方法解决该问题,但建议使用第二种方法.

  [1]:锁对象(ReentrantLock)和条件对象(Condition):

    使用代码来说明(利用银行转钱的例子来说明):

package book_14.synch;

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

/**
 * 同步(使用锁对象和条件对象)
 * @author Administrator
 *
 */
public class Bank {
    
    private final double[] accounts; // 银行账户的数量
    private Lock bankLock; // 创建锁对象
    private Condition sufficientFunds; // 创建条件对象
    
  /**
     * 构造方法
     * @param n 账户的总数量
     * @param initialBalabce 账户余额的初始值
     */    public Bank(int n, double initialBalabce){
        accounts = new double[n];
        Arrays.fill(accounts, initialBalabce);
        bankLock = new ReentrantLock();
        sufficientFunds = bankLock.newCondition(); // 获得一个条件对象
    }
    /**
     * 转钱的过程
     * @param from 转出账户的下标
     * @param to 装入账户的下标
     * @param amount 转入的金额
     * @throws InterruptedException
     */
    public void transfer(int from, int to, double amount) throws InterruptedException{
        bankLock.lock(); // 加锁
        try {
            while(accounts[from] < amount) // 余额不足时
                sufficientFunds.await(); // 等待
            System.out.print(Thread.currentThread());
            accounts[from] -= amount;
            System.out.printf(" %10.2f from %d to %d", amount, from, to);
            accounts[to] += amount;
            System.out.printf(" Total Balance: %10.2f%n", getTotalBanlance());
            sufficientFunds.signalAll(); // 唤醒所有的等待线程
        } finally {
            bankLock.unlock(); // 释放锁
        }
    }
    /**
     * 获取总金额的方法
     * @return 总金额
     */
    public double getTotalBanlance(){
        bankLock.lock(); // 加锁
        try {
            double sum = 0;
            for(double d : accounts){
                sum += d;
            }
            return sum;
        } finally {
            bankLock.unlock(); // 释放锁
        }
    }
    
    public int size(){
        return accounts.length;
    }
}
测试方法:
public class SynchBankTest {
    public static final int NACCOUNTS = 100; // 100个账户
    public static final double INITIAL_BANANCE = 1000; // 初始值1000
    public static final double MAX_AMOUNT = 1000; // 最大的转钱金额
    public static final int DELAY = 10; // 睡眠最大时间
    public static void main(String[] args) {
        Bank bank = new Bank(NACCOUNTS, INITIAL_BANANCE);
        for(int i = 0; i < NACCOUNTS; i++){
            int fromAccount = i;
            Runnable r = () ->{ // 多线程
                try {
                    while(true){
                        int toAccount = (int)(bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int)(DELAY * Math.random()));
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                }
                
            };
            Thread t = new Thread(r);
            t.start();
        }     
    }
}
  [2].使用synchronized关键字(有两种方式:同步方法和同步代码块,这使用同步方法,同步代码块将在下一章的生产消费者例子中展示)
package book_14.synch;

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

/**
 * 同步(使用synchronized):
 *         同步代码块和同步方法.
 */
public class Bank2 {
    
    private final double[] accounts; // 账户数量
    
    public Bank2(int n, double initialBalabce){
        accounts = new double[n];
        Arrays.fill(accounts, initialBalabce); // 为每个账户赋值
    }
    // 使用synchronized关键字
    public synchronized void transfer(int from, int to, double amount) throws InterruptedException{
        
        while(accounts[from] < amount)
            wait(); // 等待
        System.out.print(Thread.currentThread());
        accounts[from] -= amount;
        System.out.printf(" %10.2f from %d to %d", amount, from, to);
        accounts[to] += amount;
        System.out.printf(" Total Balance: %10.2f%n", getTotalBanlance());
        notifyAll(); // 不要使用notify(),容易造成死锁
        
    }
    // 使用synchronized关键字
    public synchronized double getTotalBanlance(){
        double sum = 0;
        for(double d : accounts){
            sum += d;
        }
        return sum;
    }
    
    public int size(){
        return accounts.length;
    }
}
至于测试方法都相同
当然还有其他的方法,最常用的就这两种

 



















































































































































以上是关于Java多线程的主要内容,如果未能解决你的问题,请参考以下文章

什么是JAVA的多线程?

Java多线程 1.认识Java线程

Java多线程 5.栅栏

java 如何实现多线程

java中啥叫做线程?啥叫多线程?多线程的特点是啥

Java多线程-Java多线程概述