day_22_线程
创建线程有两种方式,启动线程只有一种方式,调用start()
- 继承Thread类,并覆写run方法
public class Theard_01 {
public static void main(String[]args){
//创建线程对象
Thread t = new Processor();
//启动,会自动执行run方法
t.start();
for(int i = 0;i<10;i++){
System.out.println("main"+i);
}
}
}
class Processor extends Thread{
public void run(){
for(int i = 0;i<10;i++){
System.out.println("测试线程"+i);
}
}
}
第二种方式;实现Runnable接口并覆写run方法
public class Thread_02 {
public static void main(String[]args){
//创建对象
Thread thread = new Thread(new Processor1());
thread.start();
for(int i=0;i<10;i++){
System.out.println("main"+i);
}
}
}
class Processor1 implements Runnable{
@Override
public void run() {
for(int i =0;i<10;i++){
System.out.println("xiancheng"+i);
// TODO Auto-generated method stub
}
}
}
- 优先级 1-10
- Thread类中提供了三个常量用来保存优先级
-
最高 : 10 Thread.MAX_PRIORITY
-
正常 : 5 Thread.NORM_PRIORITY
-
最低 : 1 Thread.MIN_PRIORITY
- getPriority() 获取该线程优先级
- setPriority() 设置优先级
- 线程创建时继承父线程的优先级 Thread的优先级是5
低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用
*/
public class Thread_03 {
public static void main(String[]args){
Thread thread = new Processer2();
// 设置 thread线程对象的 优先级为10
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
// currentThread : 静态方法,获取当前线程对象
// 设置main方法优先级为1
Thread.currentThread().setPriority(1);
for (int i = 0; i < 10; i++) {
System.out.println("main线程 : "+i);
}
}
}
class Processer2 extends Thread{
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println("测试线程 : "+i);
}
}
}
线程 生命周期
*
- 创建 , 就绪 , 运行 , 阻塞 (就绪,运行,阻塞…), 死亡
- static currentThread() : 静态方法,用于获取当前线程的对象,写在哪个线程中,就获取哪个线程的对象
- static sleep(long m) : 静态方法,让当前线程睡眠,需要传入对应的毫秒数,写在哪个线程就睡眠哪个线程
*/
public class Thread_04 {
public static void main(String[]args){
Thread t1 = new Thread(new Processer());
Thread t2 = new Thread(new Processer());
// t1和t2在创建对象时,就已经生成名字,Thread-0和Thread-1
// 所以 就算此时把t1线程名字改为t1 , 那么 t2线程的名字 还是Thread-1
t1.setName("t1");
t2.setName("t2");
// 启动线程,进入就绪
t1.start();
t2.start();
for (int i = 0; i < 10; i++) {
// 静态方法,获取当前线程对象
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class Processer implements Runnable{
@Override
public void run() {
for(int i =0;i<10;i++){
// 获取当前线程对象,并调用getName
// 由于没有继承Thread类 所以不能使用this直接调用Thread相对应的方法,因为没有继承了
// 所以需要获取当前线程对象,再调用
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}// TODO Auto-generated method stub
}
}
唤醒线程:
-
1正常唤醒,睡眠时间够了
-
2异常唤醒,强制打断睡眠,会报异常
*/
public class Thread_05 {
public static void main(String[]args){
Thread t1=new Processer3();
t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//1秒后唤醒进程
t1.interrupt();
}
}
class Processer3 extends Thread{
public void run(){
try{
Thread.sleep(3000000);
System.out.println("自然唤醒");
}catch(InterruptedException e) {
e.printStackTrace();
System.out.println("强制唤醒");
}
System.out.println("jinchengyunxing");
}
}
//Join : 线行程合并,让指定线程在该线程运行完之后再执`
public class Thread_06 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Processer_04());
thread.setName("t1");
thread.start();
// 这句话开始,当前线程(也就是main),需要等待thread线程执行完之后,再继续执行
thread.join();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " = " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Processer_04 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " = " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
hread.yeild : 暂停当前正在执行的线程,并执行其他线程
*
- 1 静态方法,意味着 写在哪个线程 , 哪个线程就让位
- 2 给相同的优先级线程让位,不同优先级不让位
- 3 该当前线程执行的执行的时候(拿到了时间片),把该执行机会(时间片) 让给其他线程
*/
public class Thread_07 {
public static void main(String[] args) {
Thread t1 = new Processor_05();
t1.setName("t1");
t1.start();
for (int i = 0; i < 10; i++) {
System.out.println("main = "+i);
}
}
}
class Processor_05 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10 ; i++) {
// 让位
Thread.yield();
// 由于继承的Thread类 所以可以直接调用getName方法
System.out.println(getName()+" = "+i);
}
}
- stop : 终止一个线程,容易出现问题,不太安全,不推荐使用
- 可以使用标识符的形式来结束
public class Thread_08 {
public static void main(String[] args) {
Processor_06 t1 = new Processor_06();
t1.setName("t1");
t1.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 3秒后 终止 t1 线程
// 使用stop终止,容易出现问题
// t1.stop();
// 使用标识符解决
t1.isStop = true;
}
}
class Processor_06 extends Thread {
// 如果是true 就终止线程
boolean isStop = false;
@Override
public void run() {
for (int i = 0; true; i++) {
// 判断是否终止
if (isStop) {
break;
}
System.out.println(Thread.currentThread().getName() + " = " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程同步 : 当多个线程操作同一个数据的时候,为了保证数据的一致 线程同步本质就是数据同步,是一种安全机制
*
- 异步编程 : 线程之间是完全独立的,谁的运行也不会受到别的线程的影响
- 同步编程 : 线程之间不是独立的,相互之间是有影响的,某个功能必须必只能让一个线程同时执行,主要为了数据安全
- 同步的原因 : 1 数据同步,为了数据安全,某种情况来讲,同步可以理解为暂时把多线程转换为单线程 2 什么时候需要同步 1
- 必须多线程(单线程没有啥并发和冲突的情况) 2 多个线程有可能同时操作同一个数据的可能性 3 主要是数据的更改操作
- 只要对方法加上 synchronized的成员方法,就代表该方法不能被多个线程同时访问
*/
//锁是每个对象都有的,synchronized只是把锁锁住的一个持续动作,而多个线程必须保存同一个对象,才能使用同一把锁,才能相互排斥,才能保证数据安全
// 如果多个线程之间保存的不是同一个对象,尽管是同一个类的不同对象,也是没有办法相互排斥的
public class Thread_09 {
public static void main(String[] args) {
// 创建账户对象,余额为5000
Account account = new Account(5000);
// 两个线程对象保存同一个账户对象
Thread t1 = new Thread(new Processer7(account));
Thread t2 = new Thread(new Processer7(account));
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
class Processer7 implements Runnable{
private Account account;
public Processer7(Account account) {
super();
this.account = account;
}
@Override
public void run() {
account.withDraw(1000);
System.out.println(Thread.currentThread().getName()
+ " 取款成功,取款1000元,余额是 : " + account.getBalance());
// TODO Auto-generated method stub
}
}
class Account{
private double balance;
public Account(double balance) {
super();
this.balance = balance;
}
public Account() {
super();
// TODO Auto-generated constructor stub
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
//取钱方法
public synchronized void withDraw(double money){
double after = balance-money;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
balance = after;
}
}
Lock : 可以锁代码块,并且性能较好,不用频繁的去调度线程
- 并且开启加锁和关闭锁 都是需要手动的 又称为 显示锁
- 而 synchronized是隐式锁,超出作用域 自动解锁
- 1.Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是 隐式锁,出了作用域自动释放
2.Lock只有代码块锁,synchronized有代码块锁和方法锁
3.使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
优先使用顺序:
Lock 同步代码块(已经进入了方法体,分配了相应资源)
public class Thread_10 {
public static void main(String[] args) {
ATM atm = new ATM(5000);
Thread t1 = new Thread(new Processor_08(atm));
Thread t2 = new Thread(new Processor_08(atm));
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
}
//线程类
class Processor_08 implements Runnable {
// 保存账户 对象
private ATM atm;
public Processor_08(ATM atm) {
this.atm = atm;
}
@Override
public void run() {
atm.withDraw(1000);
}
}
class ATM {
private double balance;
// 锁
private Lock lock = new ReentrantLock();
public ATM(double balance) {
super();
this.balance = balance;
}
public void withDraw(double money) {
System.out.println(Thread.currentThread().getName() + " 进来了");
// ---- 非访问数据区域,不需要同步
// 开启锁 , 数据同步
lock.lock();
try {
double after = balance - money;
balance = after;
System.out.println(Thread.currentThread().getName() + "取钱成功,取钱"
+ money + ",剩余" + balance + "元");
}finally{
// 解锁
lock.unlock();
}
}
}