一、Thread 常用的方法及性质:
* 1.start() :启动线程并执行相应的run()方法* 2.run():子线程要执行的代码放在run()里面
* 3.currentThread(): 静态的,点取当前的线程
* 4.getName():获取线程的名字
* 5.setName():设置线程的名字
* 6.yield():调用此方法的线程释放当前CPU的执行权
* 7.jojn():在A线程中调用B线程的此方法,表示A线程停止执行直至B执行完毕,A线程在接着执行join()之后的代码
* 8.isAlive(): 判断当前线程是否活着
* 9.sleep(long l):显示的让当前线程睡眠l毫秒
* 10.线程通信:wait(),notify(),notifyAll()
*
* 设置线程的优先级:
* getPriority():返回线程的优先级
* setPriority(int newPrioritty):改变线程的优先级
*
* 一个线程只能执行一次start()
* Runnable 接口要比Thread 类更好的实现数据共享,而不是唯一。
* 死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了死锁。(处理线程同步时,容易出现)
二、多线程卖票机制
* 线程安全问题存在的原因?
* 由于一个线程在操作共享数据过程中,未执行完毕的情况下,另外的线程参与进来,导致共享数据存在安全问题。
* 如何解决线程的安全问题?
* 必须让一个线程操作完共享数据后,其他线程才有机会参与操作共享数据。
* Java如何实现线程的安全:线程的同步机制
* 方式一:同步代码块
* synchronized(同步监视器){
* //需要被同步的代码块(即操作共享数据的代码)
* }
* 1.共享数据:多个线程共同操作的同一个数据(变量)
* 2.同步监视器:由一个类的对象来充当,哪个线程获取此监视器,谁就执行大括号里面被同步的代码。俗称:锁。
* 方式二:同步方法:将操作共享数据的方法声明为synchronized。即此方法为同步方法,能够保证当其中一个线程执行此方法时
* 其他线程在外等待直至此线程执行完该方法
* 1.同步方法的锁:this.(应当实现Runbable 接口,此时的this代表的是同一个对象)
* 2.如果是用选择继承 Thread 的话,此时不应该使用同步方法;因为同步方法的锁就是当前对象,这样对于每个继承
* Thread 的对象都是一个独立的锁,不能达到同步的目的。
* 线程同步的弊端:由于同一个时间只能有一个线程访问共享数据,效率变低了。
三、线程通信
/*
* 线程通信:如下的三个关键字使用的话,都得在同步代码块或同步方法中。
* wait():线程的等待,一旦一个线程执行到wait(),就释放当前的锁。
* notify()/notifyAll():唤醒wait的一个或所有的线程
*
* 使用两个打印1-100,线程1、2,交替打印。
*/
class PrintNum implements Runnable{
int num = 1;
public void run(){
while(true){
synchronized (this) {
notify();//唤醒线程
if (num <= 100) {
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + num++);
} else {
break;
}
try {
wait(); //等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class testCommunication {
public static void main(String[] args) {
PrintNum p1 = new PrintNum();
Thread t1 = new Thread(p1, "打印机甲");
Thread t2 = new Thread(p1, "打印机乙");
t1.start();
t2.start();
}
}
四、常用案列
1.懒汉式
//关于懒汉式线程安全问题:使用同步机制
//对于一般的方法内,使用同步代码块,可以考虑使用this
//对于静态方法而言,使用当前本类充当锁
public class TestSingleton {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
class Singleton{
private Singleton(){
}
private static Singleton instance = null;
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
二、账户存钱
/*
* 有一个银行账号,余额为0,现在有两个用户,向你们存钱,每次存1000,一共存三次,存完后,余额3000.
*
* 1.线程同步。
* 2.数据共享
*/
class Account {
double balance;// 余额
public Account() {
}
// 存钱
public synchronized void deposit(double amt) {//这里的锁相当于this
balance += amt;
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + balance + "¥");
}
}
class Customer extends Thread {
Account account;
public Customer(Account account) {
this.account = account;
}
public void run() {
for (int i = 0; i < 3; i++)
account.deposit(1000);
}
}
public class testThread2 {
public static void main(String[] args) {
Account account = new Account(); //同一个对象,相当于一把锁,保证了同步问题。
Customer c1 = new Customer(account);
Customer c2 = new Customer(account);
c1.setName("甲");
c2.setName("乙");
c1.start();
c2.start();
}
}
三、生产者和消费者问题
/* * 生产者和消费者问题: * 生产者将生产的商品交给店员,店员负责给消费者提供商品;店员的货架上最多只能存放20件商品,当放满后,应该通知生产者暂停一下 * 当货架上的商品为0时,应该告知消费者稍等一下。 * * 分析: * 1.多线程问题(生产者和消费者) * 2.涉及到共享数据,应当考虑安全 * 3.共享数据-产品的数量 * 4.涉及到线程的通信 */ class Clerk{ //店员 int produce; public synchronized void addProduce(){ if(produce >= 20){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ produce++; System.out.println(Thread.currentThread().getName()+" :生产了第"+produce+"件商品"); try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } notifyAll(); } } public synchronized void consumeProduce(){ if(produce <= 0){ try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" :消费第"+produce+"件商品"); produce--; notify(); } } } class Producer implements Runnable{ //生产者 Clerk clerk; public Producer(Clerk clerk) { this.clerk = clerk; } @Override public void run() { System.out.println("生产者开始生产商品:"); try { Thread.currentThread().sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } while(true){ clerk.addProduce(); } } } class Consume implements Runnable{ Clerk clerk; public Consume(Clerk clerk){ this.clerk = clerk; } @Override public void run() { System.out.println("消费者开始消费商品:"); try { Thread.currentThread().sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } while(true){ clerk.consumeProduce(); } } } public class testProduceConsume { public static void main(String[] args) { Clerk clerk = new Clerk(); Producer p1 = new Producer(clerk); Producer p2 = new Producer(clerk); Producer p3 = new Producer(clerk); Producer p4 = new Producer(clerk); Consume c1 = new Consume(clerk); Consume c2 = new Consume(clerk); Consume c3 = new Consume(clerk); Thread t1 = new Thread(p1, "生产者1"); Thread t2 = new Thread(p2, "生产者2"); Thread t3 = new Thread(p3, "生产者3"); Thread t4 = new Thread(p4, "生产者4"); Thread T1 = new Thread(c1, "消费者1"); Thread T2 = new Thread(c2, "消费者2"); Thread T3 = new Thread(c3, "消费者3"); t1.start(); t2.start(); t3.start(); t4.start(); T1.start(); T2.start(); T3.start(); } }