线程
线程创建
- 继承Thread,重写run方法
- 实现Runnable接口,实现run方法
- 实现Callable接口,实现call方法(带返回值)
//创建服务
ExecutorService service= Executors.newFixedThreadPool(1);
//提交执行
Future submit = service.submit(callDemo1);
//获取结果
System.out.println(submit.get());
//关闭线程
service.shutdown();
常用方法
- start()(开启线程)
- sleep(1000)(休眠1秒,不释放锁)
- setName()(设置线程的名字)
- getName()(获取线程的名字)
- getPriority()(获得当前的优先权,最高10,最低1,默认5。)
- interrupt()(终止休眠)
Thread thread = new Thread(new SleepDemo1());
thread.setName("小花");//设置线程名字
thread.start();//开启线程
System.out.println(thread.getName());//获取线程名
System.out.println(thread.getPriority());//获取优先级,默认为5
try {
Thread.sleep(1000*5);//5秒后
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();//终止休眠,实际上就是在thread这个线程休眠的时候出异常,这样就会直接执行catch的语句,终止休眠。
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开启了");
try {
Thread.sleep(1000*60*24);//睡一天
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束了");
}
//小花
//5
//小花开启了
//java.lang.InterruptedException: sleep interrupted
// at java.lang.Thread.sleep(Native Method)
// at base.线程.SleepDemo1.run(SleepDemo1.java:31)
// at java.lang.Thread.run(Thread.java:748)
//小花结束了
- yield()(礼让线程)
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if(i%5==0){
Thread.yield();//礼让线程,让当前线程回到就绪状态,重新开始抢夺时间片。可能抢到也可能抢不到。
}
System.out.println(Thread.currentThread().getName()+"-->已下载"+i+"%。");
}
}
public static void main(String[] args) {
new Thread(new RunnableDemo1(),"图片").start();
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName()+"正在执行"+i+"。");
}
}
//main正在执行15。
//图片-->已下载1%。
//图片-->已下载2%。
//图片-->已下载3%。
//图片-->已下载4%。结束后i=5,执行yield()
此时图片线程又抢到了时间片,继续执行run()
//图片-->已下载5%。
//图片-->已下载6%。
//图片-->已下载7%。
//图片-->已下载8%。
//图片-->已下载9%。
//图片-->已下载10%。
//图片-->已下载11%。
此时main线程抢到了时间片,继续执行run()
//main正在执行16。
//main正在执行17。
//main正在执行18。
//main正在执行19。
- join()(合并线程)
try {
t1.join();//合并线程。将t1线程合并到当前线程main,让当前线程阻塞,直到t1线程执行完。
} catch (InterruptedException e) {
e.printStackTrace();
}
- setDeamon()(设置成守护线程)
线程分为用户线程和守护线程。只有当所有用户线程都结束,守护线程才会结束。
- wait()(wait其实是Object的方法,线程等待并释放锁)
- notify()(恢复当前等待的线程,不释放锁)
- notifyAll()(恢复所有等待的线程)
public class ProducerDemo2 {
public static void main(String[] args) {
List list = new ArrayList();
new Thread(new Producer1(list), "A").start();
new Thread(new Customer1(list), "B").start();
}
}
class Producer1 implements Runnable {
private List list;
public Producer1(List list) {
this.list = list;
}
@Override
public void run() {
while (true) {
synchronized (list) {
//仓库满了
if (list.size() > 0) {
try {
list.wait();//当前线程等待,执行另外的线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//仓库空了
Object obj = new Object();
list.add(obj);//生产一个
System.out.println(Thread.currentThread().getName() + "生产了-->" + obj);
list.notifyAll();//释放所有等待的线程
}
}
}
}
class Customer1 implements Runnable {
private List list;
public Customer1(List list) {
this.list = list;
}
@Override
public void run() {
while (true) {
synchronized (list) {
//仓库空了
if (list.size() == 0) {
try {
list.wait();//线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//仓库满了就要消费了
Object obj = list.remove(0);//消费一个
System.out.println(Thread.currentThread().getName() + "消费了-->" + obj);
list.notifyAll();//释放所有等待的线程
}
}
}
}
线程安全
触发条件
- 多线程并发
- 有共享数据
- 共享数据有修改操作
public class BackDemo1 {
public static void main(String[] args) {
Account act=new Account(10000);
//两个线程对同一个对象操作
new Thread(new Bank(act),"A").start();
new Thread(new Bank(act),"B").start();
//A还剩5000.0
//B还剩5000.0
}
}
class Account {
//账户余额
private double balance;
public Account(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
//取钱
void getMoney(double money){
double before = this.getBalance();
double after = before - money;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//出现线程安全问题
this.setBalance(after);
}
}
class Bank implements Runnable{
private Account act;
public Bank(Account act) {
this.act = act;
}
@Override
public void run() {
double money=5000;
act.getMoney(money);
System.out.println(Thread.currentThread().getName()+"还剩"+act.getBalance());
}
}
解决方法
synchronized(线程同步)
synchronized (共享对象){
//代码
}
1.在代码块中加上synchronized
//在代码块中加上synchronized
synchronized (this) {
double before = this.getBalance();
double after = before - money;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setBalance(after);
}
2.在方法上加synchronized
共享对象只能是this,同步范围是一整个方法。对象锁,一百个对象一百个锁。
**优点:**方便、简洁。
**缺点:**范围大,性能低。
synchronized void getMoney(double money){
double before = this.getBalance();
double after = before - money;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setBalance(after);
}
3.在静态方法上加synchronized
类锁,一百个对象一个锁。
synchronized static void getMoney(double money){
double before = this.getBalance();
double after = before - money;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setBalance(after);
}