线程是程序的一条执行线索,执行路径,是程序使用cpu的最小单位,其实说白了,线程是指进程中的一个执行流程,一个进程中可以运行多个线程,那java线程怎么做标记?下面来我们就来给大家讲解一下。
代码如下:
/* 停止线程: 1 stop 方法。 2 run 方法结束 怎么控制线程的任务结束? 任务中都会有循环结构(没有循环就不需要多线程了,开多线程就是怕这里循环影响其他),只要控制住循环就可以结束任务 控制循环通常就用定义标记来完成 */ class StopThread implements Runnable { private boolean flag = true; public void run() { while (flag) { System.out.println(Thread.currentThread() .getName() + "...."); } } public void setFlag() { flag = false; } } class StopThreadDemo { public static void main(String[] args) { StopThread st = new StopThread(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.start(); int num = 1; for (;;) { if (++num == 50) { st.setFlag(); //此处将标记变为false 停止线程 break; } System.out.println("main..." + num); } } }
java线程如何同步?
语法:
synchronized(锁对象) { 同步代码块 }
工作原理:
线程要执行同步代码块,必须先获得锁对象;
任意对象都可以作为锁对象, 任意对象都有一个内置锁;
一个锁对象最多被一个线程持有;
线程持有了锁对象后,会一直持有, 直到执行完同步代码块后才会释放锁对象;
package com.wkcto.chapter07.sync.p2; /** * 银行帐户类 * @author 蛙课网 * */ public class BankAccount { int balance = 10000; //余额 ,单位:万元 private static final Object OBJ = new Object(); //常量 //取钱的操作, 约定, 每次取钱1000 public void withdraw() { synchronized(OBJ) { //一般使用常量作为锁对象 System.out.println(Thread.currentThread() .getName() + "取钱 前, 余额为:" + balance); balance -= 1000; System.out.println(Thread.currentThread() .getName() + "取了1000万后, 余额为:" + balance); } /* * 1) xiaoming获得了CPU执行权, 执行withdraw()方法, 先获得OBJ锁对象, 执行同步代码块 * 2) xiaoming在执行同步代码块期间, CPU执行权被baby抢走了, xiaoming转为就绪状态 * babay获得CPU执行权, 要也执行同步代码块, 必须先获得OBJ锁对象, * 现在OBJ锁对象被xiaoming持有, baby线程转到等待锁对象池中阻塞 * 3) xiaoming重新获得CPU执行权, 继续执行同步代码块, 执行完同步代码块后, 释放OBJ锁对象 * 4) 等待锁对象池中的baby如果获得了锁对象, 转为就绪状态 */ } }
package com.wkcto.chapter07.sync.p2; /** * 定义一个线程类,模拟 从银行帐户 中取钱 * @author 蛙课网 * */ public class PersonThread extends Thread { private BankAccount bankaccount; //银行帐户 public PersonThread(BankAccount bankaccount) { super(); this.bankaccount = bankaccount; } @Override public void run() { bankaccount.withdraw(); } }
package com.wkcto.chapter07.sync.p2; /** * 使用线程模拟多人同时从某一帐户中取钱 * 线程同步 * @author 蛙课网 * */ public class Test01 { public static void main(String[] args) { //先开户 BankAccount account = new BankAccount(); //定义三个线程模拟三个人, 是从同一个帐户中取钱 PersonThread xiaoming = new PersonThread(account); PersonThread bingbing = new PersonThread(account); PersonThread baby = new PersonThread(account); xiaoming.setName("xiaoming"); bingbing.setName("bingbing"); baby.setName("baby"); xiaoming.start(); bingbing.start(); baby.start(); } }
同步代码块
同步代码块要想实现同步,必须保证使用同一个锁对象
只要使用了同一个锁对象的同步代码块就可以同步
package com.wkcto.chapter07.sync.p3; /** * 同步代码块, 只要使用相同的锁对象就可以实现同步 * @author 蛙课网 * */ public class Test01 { public static void main(String[] args) { PrintNum pNum = new PrintNum(); //创建线程,调用m1() new Thread(new Runnable() { @Override public void run() { pNum.m1(); } }) .start(); //创建线程,调用m2() new Thread(new Runnable() { @Override public void run() { //pNum.m2();//当使用this对象作为锁对象时, 可以同步 new PrintNum() .m2(); //使用this作为锁对象, 不能同步, 与第一个线程的锁对象不是一个 } }) .start(); } }
package com.wkcto.chapter07.sync.p3; /** * 定义类 * 提供两个 方法,分别打印字符串 * @author 蛙课网 * */ public class PrintNum { private static final Object OBJ = new Object(); //定义常量 public void m1() { //synchronized (OBJ) {//经常使用常量作为锁对象 synchronized(this) { //有时也会使用this作为锁对象 , 就是调用m1()方法的对象 for (int i = 1; i <= 200; i++) { System.out.println("wkcto is NB website"); } } } public void m2() { //synchronized (OBJ) { synchronized(this) { for (int i = 1; i <= 200; i++) { System.out.println("bjpowernode is a good school"); } } } }
ackage com.wkcto.chapter07.sync.p4; /** * 使用当前类的运行时类作为锁对象 * @author 蛙课网 * */ public class Test02 { public static void main(String[] args) { //创建线程, 打印wkcto new Thread(new Runnable() { @Override public void run() { while (true) { printText("wkcto"); } } }) .start(); //创建线程, 打印bjpowernode new Thread(new Runnable() { @Override public void run() { while (true) { printText("bjpowernode"); } } }) .start(); } private static final Object OBJ = new Object(); //常量 //静态方法,打印一个字符串 public static void printText(String text) { //synchronized (OBJ) { synchronized(Test02.class) { //使用当前类的运行时类对象作为锁对象, 有人把它称为类锁 //可以简单的理解 为把当前类的字节码文件作为锁对象 for (int i = 0; i < text.length(); i++) { System.out.print(text.charAt(i)); } System.out.println(); } } }
同步方法
package com.wkcto.chapter07.sync.p5; /** * 同步实例方法, 就是把整个方法体作为同步代码块, 默认锁对象 是this对象 */ public class Test01 { public static void main(String[] args) { Test01 obj = new Test01(); //创建线程, 调用m1() new Thread(new Runnable() { @Override public void run() { obj.m1(); } }) .start(); //创建线程, 调用m2() new Thread(new Runnable() { @Override public void run() { obj.m2(); } }) .start(); } /* * 把整个方法体作为同步代码块,并且使用this作为锁对象时, 可以直接使用synchronized修饰方法, 称为同步方法 * 同步实例方法, 就是把整个方法体作为同步代码块, 默认锁对象 是this对象 */ public synchronized void m1() { for (int i = 1; i <= 500; i++) { System.out.println(Thread.currentThread() .getName() + "-->" + i); } } public void m2() { synchronized(this) { for (int i = 1; i <= 500; i++) { System.out.println(Thread.currentThread() .getName() + "======>" + i); } } } }
package com.wkcto.chapter07.sync.p5; /** * 同步静态方法, 就是把整个方法体作为同步代码块, 默认锁对象 是当前类的运行时类对象 */ public class Test02 { public static void main(String[] args) { //创建线程, 调用m1() new Thread(new Runnable() { @Override public void run() { Test02.m1(); } }) .start(); //创建线程, 调用m2() new Thread(new Runnable() { @Override public void run() { Test02.m2(); } }) .start(); } /* * 把整个方法体作为同步代码块,并且使用当前类的运行时类对象(Test02.class)作为锁对象时, 可以直接使用synchronized修饰方法, 称为同步方法 * 同步静态方法, 就是把整个方法体作为同步代码块, 默认锁对象 是当前类的运行时类对象(Test02.class) */ public synchronized static void m1() { for (int i = 1; i <= 500; i++) { System.out.println(Thread.currentThread() .getName() + "-->" + i); } } public static void m2() { synchronized(Test02.class) { for (int i = 1; i <= 500; i++) { System.out.println(Thread.currentThread() .getName() + "======>" + i); } } } }
线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏,所以对于同步,要时刻清醒在哪个对象上同步,这是关键!最后大家如果想要了解更多java入门知识,敬请关注奇Q工具网。
推荐阅读: