Java-学习多线程总结上

多线程

1. 多线程的基本概念

  • 每一个正在执行的程序都是一个进程,资源只有一块,所以在同一时间段会有多个程序同时执行,但是在一个时间点上,只能由一个程序执行,多线程是在一个进程的基础之上的进一步划分,因为进程的启动所消耗的时间是非常长的,所以在进程之上的进一步划分就变得非常的重要,而且性能也会有所提高,所有的线程一定要依附进程才能够存在,那么进程一旦消失,线程也一定会消失,但反过来不一定,而Java是支持多线程的开发语言之一。

2. 多线程的优缺点

  • 优点:
    1.提高资源利用率
    2.提升用户体验
  • 缺点:
    1.降低了其它线程的执行概率
    2.用户会感到一点的卡顿问题
    3.给系统增加了资源压力
    4.多线程下的共享资源问题,线程冲突,安全问题

3. 多线程的实现

在Java之中,如果想实现多线程,就必须依靠一个线程的主体类,但是这个线程的主体类在定义的时候需要有一些特殊的要求,这个类可以继承Thread类或者实现Runnable接口来完成定义。

3.1 继承Thread类:
  1. Thread类是Java当中的一个线程类,Thread是Runnable接口的一个实现类,同时提供了很多线程的操作方法。
  2. 通过自定义一个继承了Thread类的自定义类,重写run方法,然后创建自定义线程类对象,调用start方法,启动线程。
  3. 存在单继承的问题。
/*
 * 自定义线程类MyThread1继承Thread类
 */
class MyThread1 extends Thread {
	@Override
		public void run() {
			for(int i = 0; i < 100; i++) {
				System.out.println("自定义线程类,通过继承Thread类");
			}
		}
}

public class Demo1 {
	public static void main(String[] args) {
		/*
		 * 通过继承Thread类得到线程对象
		 */
		MyThread1 myThread1 = new MyThread1();
		myThread1.start();
	}
}
3.2 实现Runnable接口:
  1. 自定义线程类遵从Runnable接口,重写run方法。
  2. Runnable接口当中只有一个run方法,所有通过遵从Runnable接口实现的自定义线程类在启动的时候需要通过Thread类中的start方法来启动。
  3. 使用自定义的线程类对象作为Thread类构造方法的参数,得到一个Thread类对象,再调用start方法开启线程。Thread thread = new Thread(Runnable target)。
/*
 * 自定义线程类MyThread2遵从Runnable接口
 */
class MyThread2 implements Runnable {

	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			System.out.println("自定义线程类,通过遵从Runnable接口");
		}
	}
}

public class Demo1 {
	public static void main(String[] args) {
		/*
		 * 通过遵从Runnable接口得到线程对象
		 */
		Thread thread = new Thread(new MyThread2());
		thread.start();
	}
}
3.3 继承Thread类和实现Runnable接口的区别:
  • 多线程的两种实现方式都需要一个线程的主类,而这个主类可以是通过继承Thread类或者实现Runnable接口,但是不管哪一种方式,都需要在子类当中重写run方法。
  • Thread类是Runnable接口的一个子类,使用Runnable接口可以避免单继承局限,以及更方便的表示数据共享的概念。
3.4 提问:每次重写run方法之后,需要调用start方法启动而不是直接调用run方法,但是调用start方法实际上调用的还是run方法,那为什么不直接调用run方法呢?
  1. 观察Theard类的源码中start方法的定义。
public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

private native void start0();
  1. 抛出一个IllegalThreadStateException,该异常属于RuntimeException的子类,当一个线程对象被重复调用之后,会抛出此异常,即一个线程对象只允许启动唯一的一次。
  2. 在start方法中间接调用了一个 start(0) 方法,该方法没有方法体,而且这个方法定义时使用了关键字native修饰。
  3. native关键字指的是Java本地接口调用(Java Native Interface),即使用Java调用本机操作系统的函数功能完成一些特殊的操作。
  4. 多线程的实现一定需要操作系统的支持,那么没有方法体的start(0)方法实际上就和抽象方法很类似,没有方法体但是交给JVM去实现凡是在调用的时候并不会去关心各种操作系统的如何实现start(0)方法,只会关心最终的操作结果,交给JVM去匹配不同的操作系统。
  5. 所以不直接调用run方法而是通过调用start方法间接调用run方法,除了保证每一个线程有且只能启动一次之外,还需要通过start方法去匹配当前操作系统,从而调用操作系统中的函数功能。
3.5 Thread类当中需要知道的方法:
  • Constructor:
     Thread( ):
      创建一个新的线程类对象,但是不指定目标代码,以及不指定线程名字。
     Thread(Runnable target):创建一个线程类对象,且使用Runnable接口实现类对象作为该线程的执行目标代码,不指定线程名字。
     Thread(String name):
      创建一个新的线程类对象,不指定目标代码,但是指定了该线程的名字。
     Thread(Runnable target,String name):
      创建一个新的线程类对象,使用Runnable接口实现类对象作为目标执行代码,且指定当前线程的名字。
/*
 * 线程构造方法演示
 */
public class Demo2 {
	public static void main(String[] args) {
		//不做任何要求的构造
		Thread thread = new Thread();
		
		//约束线程的名字的构造
		Thread thread2 = new Thread("朱朱");
		
		//使用Runnable接口类对象作为构造的参数
		Thread thread3 = new Thread(new Runnable() {

			@Override
			public void run() {
				System.out.println("匿名内部类对象作为线程的执行目标");
			}
			
		});
		
		//使用Runnable接口类对象作为构造的参数,且约束线程的名字
		Thread thread4 = new Thread(new Runnable() {

			@Override
			public void run() {
				System.out.println(
				"带有名字的通过RUnnable接口类对象作为执行目标的线程");
			}
		},"龙龙");
		
		System.out.println(thread);
		System.out.println(thread2);
		System.out.println(thread3);
		System.out.println(thread4);	
	}
}
  • Method:
     void setName( ):
      通过线程类对象调用,设置当前线程的名字。
     String getName( ):
      通过线程类对象调用,得到当前线程的名字。
     void setPriority(int Priority):
      通过线程类对象调用,设置当前线程的优先级。
     int getPriority( ):
      通过线程类对象调用,得到当前线程的优先级。
     void start( ):
      通过线程类对象调用,启动当前线程。
     public static void sleep(int ms):
      静态方法,通过类名直接调用,使当前所在线程代码块对应的线程进行休眠操作,休眠指定的毫秒数。
     public static Thread currentThread( ):
      静态方法,通过类名直接调用,获取当前所在线程代码块对应的线程类对象。
/*
 * Thread类成员方法演示
 */
class MyThread extends Thread {
	
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			Thread currentThread = Thread.currentThread();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("自定义线程");
	}
}

public class Demo3 {
	public static void main(String[] args) throws InterruptedException {
		Thread thread = new Thread(new Runnable() {

			@Override
			public void run() {
					System.out.println("线程目标代码");
			}
			
		},"扫雷线程");
		
		//main线程
		Thread currentThread = Thread.currentThread();
		
		System.out.println(thread.getName());
		thread.setName("纸牌线程");
		System.out.println(thread.getName());
		
		Thread.sleep(1000);
		
		System.out.println(thread.getPriority());
		thread.setPriority(Thread.MAX_PRIORITY);
		System.out.println(thread.getPriority());
	}
}
3.6 守护线程:
  1. 守护线程也称之为后台线程,伴随着主线程的存在而存在,主线程消失,守护线程也会跟着消失。
  2. 通过线程类对象调用setDeamon(boolean flag)方法设置是否为守护线程,true表示为守护线程。
public class Demo1 {
	public static void main(String[] args) throws InterruptedException {
		
		Thread thread = new Thread(new BackUpThread());
		
		// 当前线程作为一个守护线程使用
		thread.setDaemon(true);
		
		thread.start();
		
		for (int i = 0; i <= 50; i++) {
			Thread.sleep(100);
			System.out.println("主线程运行中。。。。");
		}
	}
}
发布了15 篇原创文章 · 获赞 16 · 访问量 5619

猜你喜欢

转载自blog.csdn.net/cccccv_/article/details/104717588