Java线程小结(二)
六、interrupt()
使该线程中断,如果一个线程抛出异常,可以用interrupt在catch里中断该线程.
七、构造方法
Thread()
分配新的 Thread 对象。
Thread(Runnable target)
分配新的 Thread 对象。
Thread(Runnable target, String name)
分配新的 Thread 对象。
Thread(String name)
八、常用方法
static Thread currentThread()
返回对当前正在执行的线程对象的引用。
String getName()
返回该线程的名称。
void setName(String name)
改变线程名称,使之与参数 name 相同。
int getPriority()
返回线程的优先级。
void setPriority(int newPriority)
更改线程的优先级。
void interrupt()
中断线程。
boolean isAlive()
测试线程是否处于活动状态。
boolean isDaemon()
测试该线程是否为守护线程。
void join()
等待该线程终止。
void join(long millis)
等待该线程终止的时间最长为 millis 毫秒。
void run()
如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
void setDaemon(boolean on)
将该线程标记为守护线程或用户线程。
void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
九、线程组
ThreadGroup类
ThreadGroup类来表示线程组,它可以对一批线程进行分类管理。Java允许程序直接对线程组进行控制,
案例:
package com.xiaomo.thread;
public class ThreadGroupTest {
public static void main(String[] args) throws InterruptedException {
//获取主线程所在的线程组,这是多有线程默认的线程组
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
System.out.println("主线程组的名称:"+mainGroup.getName());
System.out.println("主线程组是否是后台线程组:"+mainGroup.isDaemon());
new MyThread("新线程组");
ThreadGroup tg = new ThreadGroup("新线程组");
tg.setDaemon(true);
System.out.println("tg线程组是否是后台线程组:"+tg.isDaemon());
MyThread tt = new MyThread(tg, "tg组的线程甲");
tt.start();
//中断线程组中的所有进程
// tg.interrupt();
// Thread.sleep(20);
//返回正在活动的线程数
// System.out.println(tg.activeCount());
//设置线程组的优先级
// tg.setMaxPriority(Thread.MAX_PRIORITY);
//获取线程组的优先级
// System.out.println(tg.getMaxPriority());
new MyThread(tg, "tg组的线程乙").start();
}
}
class MyThread extends Thread {
// 提供指定先成名的构造器
public MyThread(String name) {
super(name);
}
// 提供指定线程名,线程组的构造器
public MyThread(ThreadGroup group, String name) {
super(group, name);
}
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(getName() + "线程的i变量" + i);
}
}
}
十、线程同步
Java里的多线程编程常常容易突然出现错误情况,这是由于系统的线程调度具有一定随机性,即使程序在运行过程中偶尔出现问题,是由于我们编程不当所引起的。当使用多个线程来访问同一个数据时,非常容易出现线程安全问题,所以我们用同步机制来解决这些问题。
实现同步机制有两个方法:
1,同步代码块:
synchronized(同一个数据){} 同一个数据:就是N条线程同时访问一个数据
2,同步方法:
public synchronized 数据返回类型 方法名(){}
就是使用 synchronized 来修饰某个方法,则该方法称为同步方法。对于同步方法而言,无需显示指定同步监视器,同步方法的同步监视器是 this 也就是该对象的本身,通过使用同步方法,可非常方便的将某类变成线程安全的类,具有如下特征:
1,该类的对象可以被多个线程安全的访问。
2,每个线程调用该对象的任意方法之后,都将得到正确的结果。
3,每个线程调用该对象的任意方法之后,该对象状态依然保持合理状态。
注:synchronized关键字可以修饰方法,也可以修饰代码块,但不能修饰构造器,属性等。
实现同步机制注意以下几点: 安全性高,性能低,在多线程用。性能高,安全性低,在单线程用。
1,不要对线程安全类的所有方法都进行同步,只对那些会改变共享资源方法的进行同步。
2,如果可变类有两种运行环境,当线程环境和多线程环境则应该为该可变类提供两种版本:线程安全版本和线程不安全版本(没有同步方法和同步块)。在单线程中环境中,使用线程不安全版本以保证性能,在多线程中使用线程安全版本.
Java.lang.object 里的三个方法wait() notify() notifyAll()
wait方法导致当前线程等待,直到其他线程调用同步监视器的notify方法或notifyAll方法来唤醒该线程。
wait(mills)方法
都是等待指定时间后自动苏醒,调用wait方法的当前线程会释放该同步监视器的锁定,可以不用notify或notifyAll方法把它唤醒。
notify()
唤醒在同步监视器上等待的单个线程,如果所有线程都在同步监视器上等待,则会选择唤醒其中一个线程,选择是任意性的,只有当前线程放弃对该同步监视器的锁定后,也就是使用wait方法后,才可以执行被唤醒的线程。
notifyAll()方法
唤醒在同步监视器上等待的所有的线程。只用当前线程放弃对该同步监视器的锁定后,才可以执行被唤醒的线程
案例:
package com.xiaomo.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Account {
// 封装账户编号,账户余额两个Field
private String accountNo;
private double balance;
// 账户中是否已有存款的标志
private boolean flag = false;
// 显示定义Lock对象
private final Lock lock = new ReentrantLock();
// 获得指定Lock对象对应Condition
private final Condition cond = lock.newCondition();
// 定义锁对象
private final ReentrantLock relock = new ReentrantLock();
// 构造器
public Account() {
}
public Account(String accountNo, double balance) {
this.setAccountNo(accountNo);
this.setBalance(balance);
}
public int hashCode() {
return accountNo.hashCode();
}
// 下面两个方法根据accountNo来重写hashCode()和equals()方法
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj.getClass() == Account.class) {
Account target = (Account) obj;
return target.getAccountNo().equals(accountNo);
}
return false;
}
// 提供一个线程安全的draw方法来完成取钱操作(同步方法)
public synchronized void draw(double drawAmount) {
// 账户余额大于取钱数目
if (balance >= drawAmount) {
// 吐出真钞
System.out.println(Thread.currentThread().getName() + "取钱成功!吐出真钞:"
+ drawAmount);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 修改余额
balance -= drawAmount;
System.out.println("\t 余额为:" + balance);
} else {
System.out.println(Thread.currentThread().getName() + "取钱失败!余额不足!");
}
}
// 提供一个线程安全的draw方法来完成取钱操作(同步锁)
public void acquire(double drawAmount) {
// 加锁
relock.lock();
try {
if (balance >= drawAmount) {
// 吐出真钞
System.out.println(Thread.currentThread().getName()
+ "取钱成功!吐出真钞:" + drawAmount);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 修改余额
balance -= drawAmount;
System.out.println("\t 余额为:" + balance);
} else {
System.out.println(Thread.currentThread().getName()
+ "取钱失败!余额不足!");
}
} finally {
// 修改完成,释放锁
relock.unlock();
}
}
// 同步方法的线程通信方式
public synchronized void get(double drawAmount) {
try {
// 如果flag为false,表明账户中还没有人存钱进去,取钱方法阻塞
if (!flag) {
this.wait();
} else {
if (balance >= drawAmount) {
// 执行取钱操作
System.out.println(Thread.currentThread().getName() + "取钱:"
+ drawAmount);
balance -= drawAmount;
System.out.println("账户余额为:" + balance);
// 将标志账户是否已有存款的标志设为false
flag = false;
// 唤醒其他线程
this.notifyAll();
} else {
System.out.println(Thread.currentThread().getName()
+ "取钱失败!余额不足!");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 同步方法的线程通信方式
public synchronized void deposit(double drawAmount) {
try {
// 如果flag为true,表明账户中已有人存钱进去,存钱方法阻塞
if (flag) {
this.wait();
} else {
// 执行存款操作
System.out.println(Thread.currentThread().getName() + "存钱:"
+ drawAmount);
balance += drawAmount;
System.out.println("账户余额为:" + balance);
// 将表示账户是否已有存款的标志设为true
flag = true;
// 唤醒其他线程
this.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 同步锁方式进行线程通信
public void getLock(double drawAmount) {
lock.lock();
try {
// 如果flag为true,表明账户中已有人存钱进去,存钱方法阻塞
if (!flag) {
cond.await();
} else {
if (balance >= drawAmount) {
// 执行取钱操作
System.out.println(Thread.currentThread().getName() + "取钱:"
+ drawAmount);
balance -= drawAmount;
System.out.println("账户余额为:" + balance);
// 将标志账户是否已有存款的标志设为false
flag = false;
// 唤醒其他线程
cond.signalAll();
} else {
System.out.println(Thread.currentThread().getName()
+ "取钱失败!余额不足!");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
// 同步锁方式进行线程通信
public void depositLock(double drawAmount) {
lock.lock();
try {
// 如果flag为true,表明账户中已有人存钱进去,存钱方法阻塞
if (flag) {
cond.await();
} else {
// 执行存款操作
System.out.println(Thread.currentThread().getName() + "存钱:"
+ drawAmount);
balance += drawAmount;
System.out.println("账户余额为:" + balance);
// 将表示账户是否已有存款的标志设为true
flag = true;
// 唤醒其他线程
cond.signalAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public String getAccountNo() {
return accountNo;
}
public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
出处:http://blog.csdn.net/cl05300629/article/details/13000609 作者:伫望碧落