• Java-多线程(上)


    进程与线程的概念

    进程:操作系统中一个程序的执行周期称为一个进程。

    DOS系统的时代,由于其本身就是一个单进程的操作系统,所以在同一时间段上只能够有一个程序执行。后来发展到winodws系统后,我们发现多个程序可以同时执行,所以windows是一个多进程的操作系统。

    线程:一个程序同时执行多个任务。通常,每一个任务就称为一个线程。与进程相比较,线程更"轻量级",创建、撤销一个线程比启动一个新进程开销要小的多。没有进程就没有线程,进程一旦终止,其内的线程也将不复存在。

    多进程与多线程区别:本质区别在于,每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使得线程之
    间的通信比进程之间通信更有效、更方便。

    那么,多线程表现在哪里呢?

    在实际应用中,多线程非常有用。例如,一个浏览器应用可以同时下载多个图片、音乐;一个Web服务器需要同时处理多个并发的请求。这些都是多线程的应用。

    高并发:访问的线程量非常非常高。

    高并发带来的问题:服务器内存不够用,无法处理新的请求。


    Java多线程实现

    方法1:继承Thread类实现多线程

    范例:

    class MyThread extends Thread { // 线程主体类
    	private String title;
    
    	public MyThread(String title) {
    		this.title = title;
    	}
    
    	@Override
    	public void run() { // 所有线程从此处开始执行
    		for (int i = 0; i < 10; i++) {
    			System.out.println(this.title + ",i = " + i);
    		}
    	}
    }

    正确启动多线程使用start()方法而不是run()!!!

    MyThread myThread1 = new MyThread("thread1") ;

    myThread1.start();

     

    方法2Runnable接口实现多线程

    Thread类的核心功能是进行线程的启动。如果一个类为了实现多线程直接去继承Thread类就会有但继承局限。在java中又提供有另外一种实现模式:Runnable接口。

    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }

    范例:

    class MyThread implements Runnable { // 线程主体类
    	private String title;
    
    	public MyThread(String title) {
    		this.title = title;
    	}
    
    	@Override
    	public void run() { // 所有线程从此处开始执行
    		for (int i = 0; i < 10; i++) {
    			System.out.println(this.title + ",i = " + i);
    		}
    	}
    }

    范例:使用匿名内部类进行Runnable对象创建

    public class TestDemo {
    	public static void main(String[] args) {
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				System.out.println("Hello World");
    			}
    		}).start();
    	}
    }

    范例:使用Lamdba表达式进行Runnable对象创建

    public class TestDemo {
    	public static void main(String[] args) {
    		Runnable runnable = () -> System.out.println("Hello World");
    		new Thread(runnable).start();
    	}
    }

    ThreadRunnable区别


    范例:使用Thread实现数据共享(产生若干线程进行同一数据的处理操作)

    class MyThread extends Thread {
    	private int ticket = 10; // 一共10张票
    
    	@Override
    	public void run() {
    		while (this.ticket > 0) {
    			System.out.println("剩余票数:" + this.ticket--);
    		}
    	}
    }
    
    public class TestDemo {
    	public static void main(String[] args) {
    		new MyThread().start();
    		new MyThread().start();
    		new MyThread().start();
    	}
    }

    此时启动三个线程实现卖票处理。结果变为了卖各自的票。

    范例:使用Runnable实现共享

    class MyThread implements Runnable {
    	private int ticket = 10; // 一共10张票
    
    	@Override
    	public void run() {
    		while (this.ticket > 0) {
    			System.out.println("剩余票数:" + this.ticket--);
    		}
    	}
    }
    
    public class TestDemo {
    	public static void main(String[] args) {
    		MyThread mt = new MyThread();
    		new Thread(mt).start();
    		new Thread(mt).start();
    	}
    }

    Runnable实现的多线程的程序类可以更好的描述出程序共享的概念。


    方法3Callable实现多线程:

    @FunctionalInterface
    public interface Callable<V> {
    V call() throws Exception;
    }

            Runnable中的run()方法没有返回值,它的设计也遵循了主方法的设计原则:线程开始了就别回头。但是很多时候需要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程。

    class MyThread implements Callable<String> {
    	private int ticket = 10; // 一共10张票
    
    	@Override
    	public String call() throws Exception {
    		while (this.ticket > 0) {
    			System.out.println("剩余票数:" + this.ticket--);
    		}
    		return "票卖完了,下次吧。。。";
    	}
    }
    
    public class TestDemo {
    	public static void main(String[] args) throws InterruptedException, ExecutionException {
    		FutureTask<String> task = new FutureTask<>(new MyThread());
    		new Thread(task).start();
    		new Thread(task).start();
    		System.out.println(task.get());
    	}
    }

    Thread类中提供有如下的线程名称方法:

     

    获取当前线程名字方式:Thread.currentThread().getName();

    通过以上程序我们发现,主方法本身就是一个线程,所有的线程都是通过主线程创建并启的。

    疑问:进程在哪?

    实际上每当使用了java命令去解释程序的时候,都表示启动了一个新的JVM进程。而主方法只是这个进程上的一个线程而已。


    线程的五种状态之间的相互转换


    线程休眠(sleep方法)

    线程休眠:指的是让线程暂缓执行一下,等到了预计时间之后再恢复执行。

     

    线程让步(yield()方法)

    暂停当前正在执行的线程对象,并执行其他线程。

    注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

     

    join()方法(插队方法)

    等待该线程终止。意思就是如果在主线程中调用该方法时就会让主线程休眠,让调用该方法的线程run方法先执行完毕之后在开始执行主线程。

     

    线程停止

    多线程中有三种方式可以停止线程。

    1. 设置标记位,可以使线程正常退出。

    2. 使用stop方法强制使线程退出,但是该方法不太安全所以已经被废弃了。

    3. 使用Thread类中的一个 interrupt() 可以中断线程。

     

    线程优先级

    线程的优先级指的是,线程的优先级越高越有可能先执行,但仅仅是有可能而已。

    设置优先级 public final void setPriority(int newPriority)

    取得优先级 public final int getPriority()

    1. 最高优先级:public final static int MAX_PRIORITY = 10;

    2. 中等优先级:public final static int NORM_PRIORITY = 5;

    3. 最低优先级:public final static int MIN_PRIORITY = 1;

    线程是有继承关系的,比如当A线程中启动B线程,那么BA的优先级将是一样的。

  • 相关阅读:
    如何用正确的方法写出高质量软件的75条体会(转)
    使用javascript动态添加onclick事件,
    签名和重载
    C#文件后缀名详解
    配置SQL Server 2005 Express的身份验证方式,以及如何启用sa登录名。
    CSS选择符及优先级计算
    关于软件版本的解释
    数据结构形象解释
    CSS属性选择符
    [转载]Repeater三层嵌套
  • 原文地址:https://www.cnblogs.com/yongtaochang/p/13615349.html
Copyright © 2020-2023  润新知