目录
使用实现Runnable接口创建线程的方式(存在线程安全问题)
1、start():启动当前线程;调用当前线程的run()方法 2、run():通常需要重写Thread类中的run()方法,建创建的线程执行的操作声明在此方法中 3、currentThread():静态方法,返回执行当前代码的线程 4、getName():获取当前线程的名字 5、setName():设置当前线程的名字 6、yield():释放当前CPU执行权 7、join():在线程A中,调用线程B的join()方法,此时线程A就进入阻塞状态,直到线程B执行完后,线程A才结束阻塞状态 8、stop():强制结束当前线程(已过时) 9、sleep():让当前线程阻塞一段时间(单位:毫秒) 10、isAlive():判断当前线程是否存活
> MAX_PRIORITY:10 > MIN_PRIORITY:1 > NORM_PRIORITY:5--->默认优先级
> getPriority():获取当前线程的优先级 > setPriority(int newPriority):设置线程的优先级
说明:优先级高的要先抢占线程的执行权,但只是从概率上讲,优先级高的线程高概率情况下被执行,但并不意味着只有当优先级高的线程执行完以后,低优先级的线程才开始执行
- class ThreadMethod extends Thread{
- @Override
- public void run() {
- for(int i=0;i<=25;i++){
- if(i%2==0){
-
- try {
- //阻塞一秒
- sleep(100);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- System.out.println(getName()+":"+getPriority()+":"+i);
- }
-
- if(i%20==0){
- this.yield();
- }
-
- }
- }
-
- public ThreadMethod(String name){
- super(name);
- }
- }
-
-
- public class ThreadMethodTest {
- public static void main(String[] args) {
- ThreadMethod m1=new ThreadMethod("分线程1");
- // m1.setName("线程1");
-
- //设置分线程的优先级
- m1.setPriority(Thread.MAX_PRIORITY);
- m1.start();
-
- //给主线程命名
- Thread.currentThread().setName("主线程");
- //设置主线程优先级
- Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
-
- for(int i=0;i<=25;i++){
- if(i%2==0){
- System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+":"+i);
- }
- if(i==20){
- try {
- m1.join();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
- }
- }
运行结果如下:
Java中的线程分为两类:一种是守护线程,一种是用户线程。
它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。
守护线程是用来服务用户线程的,通过在start()方法前调用 thread.setDaemon(true)可以把一个用户线程变成一个守护线程。
Java垃圾回收就是一个典型的守护线程。
若JVM中都是守护线程,当前JVM将退出。
JDK中用Thread.State类定义了线程的几种状态
要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五种状态:
以具体例题来说明线程安全问题
模拟火车站售票程序,开启三个窗口售票,总票数为100张
- public class WindowTest1 {
- public static void main(String[] args) {
- Window w1=new Window();
- Window w2=new Window();
- Window w3=new Window();
- w1.setName("窗口1");
- w2.setName("窗口2");
- w3.setName("窗口3");
- w1.start();
- w2.start();
- w3.start();
-
- }
- }
-
- class Window extends Thread{
- private static int ticket=100;
-
- @Override
- public void run() {
- while(true){
- if(ticket>0){
- System.out.println(getName()+":卖票,票号为:"+ticket);
- ticket--;
- }else{
- break;
- }
-
- }
- }
- }
部分运行结果:
- public class WindowTest2 {
- public static void main(String[] args) {
- Window2 w=new Window2();
- Thread thread1 = new Thread(w);
- Thread thread2 = new Thread(w);
- Thread thread3 = new Thread(w);
- thread1.setName("窗口1");
- thread2.setName("窗口2");
- thread3.setName("窗口3");
- thread1.start();
- thread2.start();
- thread3.start();
- }
- }
-
- class Window2 implements Runnable{
-
- private int ticket=100;
- @Override
- public void run() {
- while(true){
- if(ticket>0){
- System.out.println(Thread.currentThread().getName()+",卖票,票号为:"+ticket);
- ticket--;
- }else {
- break;
- }
- }
- }
- }
部分运行结果如下:
1. 多线程出现了安全问题
2. 问题的原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有 执行完,另一个线程参与进来执行。导致共享数据的错误。
3. 解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以 参与执行。
java对于多线程的安全问题提供了专业的解决放方式:同步机制
synchronized(同步监视器){
//需要被同步的代码;
}
说明:
使用继承Thread类的方式
- public class WindowTest1 {
- public static void main(String[] args) {
- Window w1=new Window();
- Window w2=new Window();
- Window w3=new Window();
- w1.setName("窗口1");
- w2.setName("窗口2");
- w3.setName("窗口3");
- w1.start();
- w2.start();
- w3.start();
-
- }
- }
-
- class Window extends Thread{
- private static int ticket=100;
- private static Object obj1=new Object();
-
- @Override
- public void run() {
- while(true){
- //方式二:synchronized (obj1){
- synchronized (Window.class){
- //类也是对象 相当于 Class clazz=Window.class
- //Window.class只会加载一次
- if(ticket>0){
- System.out.println(getName()+":卖票,票号为:"+ticket);
- ticket--;
- }else{
- break;
- }
- }
-
- }
- }
- }
使用实现Runnable接口的方式
- public class WindowTest2 {
- public static void main(String[] args) {
- Window2 w=new Window2();
- Thread thread1 = new Thread(w);
- Thread thread2 = new Thread(w);
- Thread thread3 = new Thread(w);
- thread1.setName("窗口1");
- thread2.setName("窗口2");
- thread3.setName("窗口3");
- thread1.start();
- thread2.start();
- thread3.start();
- }
- }
-
- class Window2 implements Runnable{
- Object obj=new Object();
- private int ticket=100;
- @Override
- public void run() {
- while(true){
- synchronized (this){ //此时的this:唯一的window2的对象 //方式二:synchronized(obj) {
- if (ticket > 0) {
- System.out.println(Thread.currentThread().getName() + ",卖票,票号为:" + ticket);
- ticket--;
- } else {
- break;
- }
- }
- }
- }
- }
如果操作共享数据的代码完整的声明在一个方法中,不妨将这个方法声明为同步的
说明:
使用继承Thread类的方式
- public class WindowTest1_2 {
- public static void main(String[] args) {
- Window1_2 w1=new Window1_2();
- Window1_2 w2=new Window1_2();
- Window1_2 w3=new Window1_2();
- w1.setName("窗口1");
- w2.setName("窗口2");
- w3.setName("窗口3");
- w1.start();
- w2.start();
- w3.start();
-
- }
- }
-
- class Window1_2 extends Thread{
- private static int ticket=100;
-
- @Override
- public void run() {
- while(true){
- show();
- }
- }
- private static synchronized void show(){//同步监视器:t1,t2,t3(此种方法是错误的)
- //必须保证此方法是静态的
- //此时的同步监视器:Window1_2
- if(ticket>0){
- System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
- ticket--;
- }
- }
- }
-
使用实现Runnable接口的方式
- public class WindowTest2_2 {
- public static void main(String[] args) {
- Window2_2 w=new Window2_2();
- Thread thread1 = new Thread(w);
- Thread thread2 = new Thread(w);
- Thread thread3 = new Thread(w);
- thread1.setName("窗口1");
- thread2.setName("窗口2");
- thread3.setName("窗口3");
- thread1.start();
- thread2.start();
- thread3.start();
- }
- }
-
- class Window2_2 implements Runnable{
-
- private int ticket=100;
- @Override
- public void run() {
- while(true){
- show();
- }
- }
- private synchronized void show(){//同步监视器:this
- if(ticket>0){
- System.out.println(Thread.currentThread().getName()+",卖票,票号为:"+ticket);
- ticket--;
- }
- }
- }