黑马程序员--Java基础--06-多线程1

来源:互联网 发布:xp系统网络ip地址设置 编辑:程序博客网 时间:2024/05/16 00:55

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------



一.线程:

 1.线程的概念:

  1).我们之前的程序都是"单线程"程序:代码一行一行执行,后面的代码总要等到前面的代码执行完毕,才能获得

    执行;如果前面的代码很复杂,或者被阻塞,后边的代码就不会被执行得到;

 2).我们可以将一些代码作为一个"独立"的线程去执行,这样在主程序,将线程启动后,这个线程中的代码就会和主

   程序的代码"并行"执行。

<span style="font-family:Microsoft YaHei;font-size:14px;">public class Demo {</span>
<span style="font-family:Microsoft YaHei;font-size:14px;">public static void main(String[] args) {/*fun1();fun2();//必须等待fun1()执行完毕fun3();//必须等到fun2()执行完毕*/MyThread1 t1 = new MyThread1();MyThread2 t2 = new MyThread2();MyThread3 t3 = new MyThread3();t1.start();t2.start();t3.start();}private static void fun1() {for(int x = 0 ;x < 100; x++){System.out.println("x = " + x);}Scanner sc = new Scanner(System.in);System.out.println("请输入:");String s = sc.next();}private static void fun2() {for(int y = 0;y < 100 ; y++){System.out.println("y = " + y );}}private static void fun3() {for(int z = 0; z < 100 ; z++){System.out.println("z = " + z);}}}</span>


<span style="font-family:Microsoft YaHei;font-size:14px;">import java.util.Scanner;public class MyThread1 extends Thread {public void run() {for(int x = 0 ;x < 100; x++){System.out.println("x = " + x);}Scanner sc = new Scanner(System.in);System.out.println("请输入:");String s = sc.next();}}</span>


<span style="font-family:Microsoft YaHei;font-size:14px;">public class MyThread2 extends Thread {@Overridepublic void run() {for(int y = 0;y < 100 ; y++){System.out.println("y = " + y );}}}</span>

<span style="font-family:Microsoft YaHei;font-size:14px;">public class MyThread3 extends Thread {@Overridepublic void run() {for(int z = 0; z < 100 ; z++){System.out.println("z = " + z);}}}</span>
二、进程

 要了解"线程"先要了解"进程":

1.进程:

    1).什么是进程:进程是操作系统的概念,它就是指在操作系统中运行的某个程序;

             每个程序对于操作系统来说都是一个独立的进程,由操作系统管理,分配内存、CPU执行时间.....

    2).什么是多进程:是指操作系统可以同时管理多个应用程序的同时运行;

    3).多进程的意义:可以充分利用CPU资源;可以使用户有更好的操作体验,可以同时运行多个程序;

2.线程:

    1).什么是线程:线程是指在一个"主进程"中,可以使某段代码以独立于主进程的方式运行。

              线程中的代码,与主进程中的代码同时抢占操作系统资源;

    2).什么是多线程:多线程是指,一个主进程可以启动多个线程,去独立运行。

    3).多线程的意义:多线程也可以充分利用CPU资源;可以使我们的几段代码"同时"运行,提高我们的代码效率;

3.并行和并发:

    1).并行:是指多个线程在"某个时间段内"同时运行;

    2).并发:是指多个线程在"某个时间点上"同时的访问同一资源;

三、线程实现方式一

  1.Java中一个线程使用"Thread"类表示;

  2.实现线程的方式:

    A.定义一个线程类,继承自Thread;

    B.重写run()方法;将要在此线程中执行的代码写到这里;

 3.启动线程:

     A--实例化一个自定义线程类的对象;

     B--调用对象的start()方法启动线程;

  4.注意:

    A.启动线程,一定要使用start()方法。调用run()不会产生编译错误,但这只是简单的方法调用,不是启动线程;

    B.不能多次的调用start()方法;


<span style="font-family:Microsoft YaHei;">public class MyThread extends Thread{</span>
<span style="font-family:Microsoft YaHei;">@Overridepublic void run() {for(int i = 0; i < 100 ; i++){System.out.println("i = " + i);}}}</span>

<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {MyThread t = new MyThread();t.start();//t.run();//这不是启动线程,这只是简单的方法调用;for(int k = 0;k < 100 ; k++){System.out.println("k = " + k);}}}</span>
四、获取和设置线程对象名称

  1.一个线程类,可以实例化多个对象,每个对象都可以以单独的线程去执行;

  2.每个线程,都有一个默认的名称,格式:"Thread-索引":

  3.设置线程名称:setName(String name):

    获取线程名称:getName();

<span style="font-family:Microsoft YaHei;">public class MyThread extends Thread {@Overridepublic void run() {for(int i = 0;i < 100 ; i++){System.out.println(this.getName() + "(i = " + i + ")");}}}</span>

<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.setName("小明");t2.setName("小红");t3.setName("小亮");t1.start();t2.start();t3.start();}}</span>
五、线程的优先级;

  1.Java中的线程优先级:从低到高:1--10

  2.默认的优先级是:5

  3.设置优先级:

   setPriority(int p):设置优先级:一定要在1--10的范围内,否则抛出异常;

   getPriority():获取线程的优先级;

  4.注意:

   1).较高的优先级,只代表有机会先被执行,但仍由操作系统管理,仍然有很多的不确定性;

   2).所以,大家不要利用"优先级"的技术,去试图向让某个线程先执行完毕;

   3).如果线程内,有较少的代码,执行逻辑很简单,那么优先级的效果就不会明显;

<span style="font-family:Microsoft YaHei;">public class MyThread extends Thread{public void run() {double sum = 0;for(int i = 1 ; i <= 10 ; i++){for(int j = 1 ; j <= 20000000 ; j++){sum += (Math.PI + Math.E) / j;if(j % 20000 == 0){Thread.yield();//退回到就绪状态}}}System.out.println(this.getName() + " 执行完毕!");};}</span>

<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();MyThread t4 = new MyThread();MyThread t5 = new MyThread();MyThread t6 = new MyThread();//设置优先级//t1.setPriority(100);//一定要在1--10的范围内,否则抛出异常;t1.setPriority(1);t2.setPriority(10);//最高优先级t3.setPriority(1);t4.setPriority(1);t5.setPriority(1);t6.setPriority(1);//设置线程名称t1.setName("线程1");t2.setName("线程2");t3.setName("线程3");t4.setName("线程4");t5.setName("线程5");t6.setName("线程6");//启动线程t1.start();t2.start();t3.start();t4.start();t5.start();t6.start();}}</span>
六、 线程的休眠:

1.public static void sleep(long millis)


<span style="font-family:Microsoft YaHei;">import java.text.SimpleDateFormat;import java.util.Date;public class MyThread extends Thread{@Overridepublic void run() {for(int i = 0; i < 10 ;i++){Date date = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String str = sdf.format(date);System.out.println(str);//休息一秒try {Thread.sleep(1000);//休眠1秒} catch (InterruptedException e) {e.printStackTrace();}}}}</span>
<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {new MyThread().start();for(int i = 0; i < 10 ;i++){Date date = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String str = sdf.format(date);System.out.println("主线程:" + str);//休息一秒try {Thread.sleep(1000);//休眠1秒} catch (InterruptedException e) {e.printStackTrace();}}}}</span>

七、加入进程
<span style="font-family:Microsoft YaHei;">public class MyThread extends Thread{public void run() {for(int i = 0;i < 100 ; i++){System.out.println(this.getName() + " 正在杀敌 i = " + i);}};}</span>

<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("兵1");t2.setName("兵2");t1.start();try {t1.join();//t2要等待t1执行完毕,再start();} catch (InterruptedException e) {e.printStackTrace();}t2.start();}}</span>

八、线程的礼让:

1. public static void yield()

  注意:礼让后,很可能会被操作系统再次分配执行,所以,不能利用这个技术

      试图让某个线程最后执行完毕;

<span style="font-family:Microsoft YaHei;">public class MyThread extends Thread{public void run() {for(int i = 0;i < 1000 ; i++){if(this.getName().equals("汪峰")){Thread.yield();//礼让:退回到"就绪"状态,有可能会被操作系统再次分配执行;}System.out.println(this.getName() + " i = " + i);}};}</span>
<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("章子怡");t2.setName("汪峰");t1.start();t2.start();}}</span>

九、守护线程:

 1. .默认情况下,当主进程开出一个线程后,都会等待线程结束后,主进程才会结束; 

    这个就是非守护线程;

 2.我们可以将线程设为"守护线程":当主进程完毕时,开出的所有守护线程也跟着结束;但是不会立即结束,会有个小缓冲;

  public final void setDaemon(boolean on);

<span style="font-family:Microsoft YaHei;">public class MyThread extends Thread {@Overridepublic void run() {for(int i = 0;i < 1000 ; i++){System.out.println(this.getName() + " 正在杀敌......i = " + i);}}}</span>
<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {MyThread t1 = new MyThread();t1.setName("小兵");//将线程设为守护线程t1.setDaemon(true);t1.start();for(int i = 0; i < 100 ;i++){System.out.println("将军正在杀敌...i = " + i);}System.out.println("将军杀敌完毕,打道回府!!");}}</span>
十、线程的中断:

  public final void stop():

  public void interrupt():基于在线程的内部,当处于以下三种阻塞状态时,才可以促使其停止:

        1).Object--wait():

        2).Thread--join():

        3).Thread--sleep():

<span style="font-family:Microsoft YaHei;">public class MyThread extends Thread {@Overridepublic void run() {for(int i = 0;i < 10 ; i++){System.out.println("我不停:i = " + i);try {Thread.sleep(1000);} catch (InterruptedException e) {System.out.println("线程出现异常了,可能是外部试图停掉我,那么好吧,拜拜......");return;}}}}</span>
<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {MyThread t1 = new MyThread();t1.start();//主进程等待3秒钟,如果线程不结束,这里给它干掉System.out.println("主进程等待3秒...");try {Thread.sleep(1000 * 3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("主进程醒来,干掉线程......");//t1.stop();t1.interrupt();}}</span>
十一、线程实现的方式二:

 1.自定义实现Runnable接口;

 2.重写run()方法;

 3.启动线程:

    1).实例化我们自定义类的对象;

    2).实例化一个Thread对象,将我们的自定义对象作为参数传递给Thread的构造方法;

    3).调用Thread对象的start()方法启动线程

<span style="font-family:Microsoft YaHei;">public class MyRunnable implements Runnable {@Overridepublic void run() {for(int i = 0;i < 100 ; i++){System.out.println("i = " + i);}}}</span>

<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {MyRunnable myRun = new MyRunnable();Thread t = new Thread(myRun);t.start();for(int k = 0 ;k < 100 ; k++){System.out.println("k = " + k);}}}</span>
十二、两种方式实现卖票

1.Thread方式实现卖票

<span style="font-family:Microsoft YaHei;">package cn.itcast.demo11__Thread方式实现卖票;public class Tickets {private int ticketNo = 100;public int getTicket(){//窗口1,窗口2if(this.ticketNo > 0){//窗口1,窗口2return this.ticketNo--;//窗口1}else{return 0;}}}</span>

<span style="font-family:Microsoft YaHei;">public class MyThread extends Thread{private Tickets tic;private int count;private TreeSet<Integer> tree = new TreeSet<>();public MyThread(Tickets t){this.tic = t;};public void run() {while(true){int t = this.tic.getTicket();if(t > 0){//System.out.println(this.getName() + " 抢到票:" + t);tree.add(t);}else{//System.out.println("没票了,不抢了");break;}}System.out.println(this.getName() + " 共抢到 : " + tree.size() + " 张票,明细:" + tree);}}</span>

<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {//1.实例化一个票池;Tickets tic = new Tickets();//2.实例化三个线程,模拟三个窗口售票MyThread t1 = new MyThread(tic);MyThread t2 = new MyThread(tic);MyThread t3 = new MyThread(tic);//3.设置线程名称t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");//4.启动线程t1.start();t2.start();t3.start();}}</span>
2.Runnable方式实现卖票;

<span style="font-family:Microsoft YaHei;">public class Tickets {private int ticketNo = 100;public int getTicket(){//窗口1,窗口2if(this.ticketNo > 0){//窗口1,窗口2return this.ticketNo--;//窗口1}else{return 0;}}}</span>

<span style="font-family:Microsoft YaHei;">public class MyRunnable implements Runnable {private Tickets tic;public MyRunnable(Tickets t){this.tic = t;}@Overridepublic void run() {while(true){int t = this.tic.getTicket();if(t > 0){System.out.println(Thread.currentThread().getName() + " 获取票:" + t);}else{break;}}}}</span>

<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {Tickets tic = new Tickets();MyRunnable m1 = new MyRunnable(tic);MyRunnable m2 = new MyRunnable(tic);MyRunnable m3 = new MyRunnable(tic);Thread t1 = new Thread(m1);Thread t2 = new Thread(m2);Thread t3 = new Thread(m3);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}}</span>
十三、并发性问题产生的原因及解决方式

 1.起因:

  1).有多线程环境

  2).有共享数据

  3).有多条语句操作共享数据

2、解决方式

使用同步解决并发访问的问题:

  1).在共享资源上(一般是一些方法)使用关键字:synchronized

  2).作用:当一个线程访问时,其它线程全部列队等待;这种机制保证了这个方法在同一时刻

       只能被一个线程访问;

  3).synchronized语法:

    1.同步代码块:

     synchronized(被锁的对象){

  //同步代码

     }

    注:被锁的对象:当一个线程访问此段代码时,会将这个对象中所有的"同步代码块"和"同步方法"加锁,

     也就意味着,一个线程访问一段同步代码块,其它线程不能访问"被锁对象"的其它"同步代码块"和"同步方法";

<span style="font-family:Microsoft YaHei;">public class Tickets {private int ticketNo = 100;public int getTicket(){//窗口1synchronized (this) {if(this.ticketNo > 0){//窗口1return this.ticketNo--;//窗口1}else{return 0;}}}}</span>

<span style="font-family:Microsoft YaHei;">import java.util.TreeSet;public class MyThread extends Thread{private Tickets tic;private int count;private TreeSet<Integer> tree = new TreeSet<>();public MyThread(Tickets t){this.tic = t;};public void run() {while(true){int t = this.tic.getTicket();if(t > 0){//System.out.println(this.getName() + " 抢到票:" + t);tree.add(t);}else{//System.out.println("没票了,不抢了");break;}}System.out.println(this.getName() + " 共抢到 : " + tree.size() + " 张票,明细:" + tree);}}</span>

<span style="font-family:Microsoft YaHei;">public class Demo {public static void main(String[] args) {//1.实例化一个票池;Tickets tic = new Tickets();//2.实例化三个线程,模拟三个窗口售票MyThread t1 = new MyThread(tic);MyThread t2 = new MyThread(tic);MyThread t3 = new MyThread(tic);//3.设置线程名称t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");//4.启动线程t1.start();t2.start();t3.start();}}</span>
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


















0 0
原创粉丝点击