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多线程的主要内容,如果未能解决你的问题,请参考以下文章