synchronized(对象){
//对于被锁住的对象的操作
}
对象:共享区
一个对象只能拥有一把对象锁
代码块里的内容:临界区
互斥线程
并发访问的线程上同步锁之后就称为线程互斥
谁抢到了对象锁的线程就先执行
没有抢到对象锁的线程就等待对象锁
加同步锁,夹在共享对象上
每一个对象都有唯一的一把锁
一般做为修饰符放在返回值后面
示例:
public synchronized void getMoney(){
}
此时被锁住的共享区的对象是this
一般同步方法用在本类的声名中
一般来讲:
同一种功能实现会提供两种版本,一种是单线程下效率较高的线程不安全版本
另一种是多线程情境下效率较低单线程安全的版本
StringBuffer
StringBuilder
ArrayList
Vector
也是操纵同一对象,可以控制线程的执行顺序
wait(),让线程等待,等待之后进入阻塞状态(等待池),需要别的线程唤醒
notify(),唤醒等待池中任意一条线程
notifyAll(),唤醒等待池中所有等待的线程
例:生产者:用来计算1+100的和。和就是产品
消费者:能够得到你这个和输出一下就可以了
生产者先执行,消费者后执行。 结果5050
消费者先执行,生产者后执行。 结果0
生产者和消费者两个是不同的逻辑,所以需要两个线程类
Sender 生产者
Printer 消费者
public class ResultTest {
public static void main(String[] args) {
//新建一个共同操作的对象result
Result r = new Result();//旗标位为false
//产生两个线程实例
Sender s = new Sender(r, "生产者");
Printer p = new Printer(r,"消费者");
//想要的结果,不管哪个先进入就绪状态,都是生产者先执行
s.start();
p.start();
}
}
// 生产者的线程类
class Sender extends Thread {
private Result result;
public Sender(Result result, String name) {
super(name);
this.result = result;
}
@Override
public void run() {
// 从0+到100
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
if(result.isFlag() == false) {
//如果当前没有等待的线程就睡眠0.2秒
//生产者线程阻塞,让出CPU的使用权,消费者跟着执行
try {
sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
result.setValue(sum);
synchronized(result) {
result.notifyAll();
}
}
}
// 消费者的线程类
class Printer extends Thread {
private Result result;
public Printer(Result result,String name) {
super(name);
this.result = result;
}
@Override
public void run() {
synchronized(result) {
try {
result.setFlag(true);
result.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("结果"+result.getValue());
}
}
旗标的代码如下
/**
* 模拟一个结果数据
*
* @author Acer
*
*/
public class Result {
private int value;
//旗标,也叫做标志位
private boolean flag;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
例2:存钱取钱
账户里面有钱才可以取,账户里面存进去钱,才可以取出钱
假设:男朋友的线程是用来存钱的,女朋友的线程是用来花钱的
public class Account {
// 属性
// 账号
private String accountNo;
// 余额
private double balance;
// 设置一个标志位来判断当前账户里有没有钱
private boolean flag;// 默认值为false,代表当前账户中没有钱
public Account() {
}
public Account(String accountNo, double balance) {
super();
this.accountNo = accountNo;
this.balance = balance;
}
// 提供一个取钱的方法
public synchronized void getMoney(double money) throws InterruptedException {
// 判断
if (flag == false) {
wait();
} else {
// 判断一下输入的钱是否大于余额
if (money <= getBalance() && money >= 0) {
System.out.println(Thread.currentThread().getName() + "本次取了" + money+"元");
// 余额的计算
setBalance(getBalance() - money);
try {
Thread.sleep(100);// 抱着锁睡的,不会释放对象锁
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("余额" + getBalance());
flag = false;
notifyAll();// 取完钱之后唤醒别的等待的线程
} else {
System.out.println("你不知道自己多少钱么");
}
}
}
public synchronized void saveMoney(double money) throws InterruptedException {
if (flag == true) {
wait();
} else {
System.out.println(Thread.currentThread().getName()+"本次存了" + money + "元");
setBalance(getBalance() + money);
System.out.println("余额" + getBalance());
flag = true;
notifyAll();
}
}
public String getaNumber() {
return accountNo;
}
public void setaNumber(String accountNo) {
this.accountNo = accountNo;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account [accountNo=" + accountNo + ", balance=" + balance + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((accountNo == null) ? 0 : accountNo.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Account other = (Account) obj;
if (accountNo == null) {
if (other.accountNo != null)
return false;
} else if (!accountNo.equals(other.accountNo))
return false;
return true;
}
}
/**
* 男朋友存钱流程
*
* @author Acer
*
*/
public class BoyThread extends Thread {
// 所操纵的数据?
private Account account;// 同一个账户
// 传递取的钱
private double money;
public BoyThread(Account a, double money, String name) {
super(name);
this.money = money;
account = a;
}
@Override
public void run() {
// 调用存钱的方法,存100次
for (int i = 1; i <= 100 ; i++) {
try {
account.saveMoney(money);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* 女朋友管卡线程类
* @author Acer
*
*/
public class GirlThread extends Thread {
// 所操作的数据?
private Account account;// 同一个账户
// 传递取的钱
private double money;
public GirlThread(Account a, double money, String name) {
super(name);
this.money = money;
account = a;
}
@Override
public void run() {
// 调用取钱的方法,连续取100次
for (int i = 0; i < 100; i++) {
try {
account.getMoney(money);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* 各自执行线程
* @author Acer
*
*/
public class CardTest {
public static void main(String[] args) {
Account a = new Account("7355608",0);
//声明两个线程
BoyThread bt = new BoyThread(a,800,"boy");
GirlThread gt = new GirlThread(a, 800, "girl");
bt.start();
gt.start();
}
}
如何发生的:两个线程都拥有对方的对象锁不能释放
如何解决:对象锁的获取顺序保持一致,完成一个较好的资源调度即可
相关代码:
package day19;
public class DeadThreadTest {
public static void main(String[] args) {
DeadThreadTest dt = new DeadThreadTest();
Dead1 d1 = new Dead1(dt);
Dead1 d2 = new Dead1(dt);
d1.start();
d2.start();
}
static class R {
int value = 0;
}
private R r1 = new R();
private R r2 = new R();
public void write() throws InterruptedException {
synchronized(r1) {
Thread.sleep(200);
synchronized(r2) {
System.out.println("write");
}
}
}
public void read() throws InterruptedException {
synchronized(r2) {
Thread.sleep(200);
synchronized(r1) {
System.out.println("read");
}
}
}
}
class Dead1 extends Thread {
private DeadThreadTest dt;
public Dead1(DeadThreadTest dt) {
this.dt=dt;
}
@Override
public void run() {
try {
dt.write();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Dead2 extends Thread {
private DeadThreadTest dt;
public Dead2(DeadThreadTest dt) {
this.dt = dt;
}
@Override
public void run() {
try {
dt.read();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
jdk提供了很多锁对象供我们去使用,如读写锁
在jdk中后缀名为lock的大部分类
使用步骤:
声明一个锁对象,在需要的地方进行lock
最后在逻辑完成之后,记得释放锁对象lock
代码实例:
private final ReentrantLock lock = new...
try{
lock.lock();
//写要被锁住的对象的执行,临界区的代码
}finally{
lock.unlock();
}
池化编程:预先创建好一定数量的线程,避免多次新建线程
打断正在睡眠的线程,如果打断正在执行的线程会报错
isInterrupted:判断当前线程是否被打断
interrupted:清空打断信息
可以调用Thread类中的非静态方法isInterrupted来返回当前线程的interrupted status的状态值。这个值只有两种情况:true和false
true 表示当前有 线程要打断我们的阻塞状态
false表示当前没有线程要打断我们的阻塞状态
今天继续学习的线程的相关内容,今天就没有昨天那么容易了,感觉还是比较绕的,上课代码也没有跟住敲,只能下来再慢慢研究,在取钱的那个相关代码还碰见了一个问题,设置取钱100次,但是程序循环只执行了50次就停下了,也没有结束,研究半天也没研究出来结果,只能等后续的再研究了.