高级API快速入门之多线程01【07】

本文详细介绍了进程与线程的概念,创建线程的两种方式(继承Thread类和实现Runnable接口),以及线程操作、安全性、同步和游戏示例。深入浅出地讲解了如何利用线程提高程序并发性能和解决数据同步问题。
摘要由CSDN通过智能技术生成

一、概念
   1. 进程与线程
         a. 进程---就是正在进行的程序。
             CPU在某一时间段只处理一个程序。 程序也是一个进程,当程序结束,进程消失。

      b. 线程---就是程序中的一个执行路径(控制单元)
             线程在控制着进程的执行;  它是真正的执行者。

   进程与线程的关系:一个进程中至少包含有一个或多个线程。


得到当前线程名:

   System.out.println(Thread.currentThread().getName());


   2. 多线程存在的意义
          多线程可以让我们的程序部分可以产生同时运行的效果,各玩各的。提高效率是其次,主要是能让多段代码同时执行。

   3. 多线程的目的:
          为了最大限度的利用CPU资源。

   4. 线程调度:
        按照特定的机制为多个线程分配CPU的使用权。

调度的模式有两种:
    (1) 分时调度:所有线程轮流获得CPU使用权,并平均分配每个线程占用CPU的时间;
    (2) 抢占式调度:根据线程的优先级别来获取CPU的使用权。
                             JVM的线程调度模式采用了抢占式模式。

 二、线程创建方式一:继承Thread类

   关键词:Thread、run()、start()
   1. Thread类创建,分两种写法:
   步骤:
            第1步:定义类继承Thread类;
            第2步:子类中重写Thread类中的run()方法;
            第3步:调用线程的start()方法   

写法一:

  子类:-------------------------------------------------
    public class Person extends Thread{
        @overriad
        public void run(){
        System.out.println("这是个线程");
        }
    }

   测试类:------------------------------------------------
       Person ps=new Person(); //初始化线程
       ps.start();             //启动线程并调用run方法


   写法二:
 

  测试类:------------------------------------------------
      new Thread(){
    @overriad
    public void run(){
        System.out.println("这是个线程");
    }
      }.start();


     1.重写run方法的目的:将自定义的代码存储在run方法中,让线程运行(也就是将同时要运行的代码写在run()方法中)
    2. 通过对象.run()调用,不用start()方法调用也可以,但run()就变成主线程中的方法,与线程没关系。 因为线程没有开启,你只执行了调用。
    3. run()方法中仅仅是封装多线程运行的代码,而start()则是开启多线程的钥匙
    4. start()方法是开启多线程,并执行run()方法
    5. 多线程的一个特性:随机性(谁抢到谁执行,至于执行多长,CPU说了算)

package javaadvan_07;
//QQ程序
public class Demo_02 {
	public static void main(String[] args) {
		
		//线程的核心:随机,灵活。
		
		//获取当前程序中的main线程
		for(int i=1;i<=1000;i++) {
			System.out.println("当前程序的main线程"+Thread.currentThread().getName());
		}
		//当前程序还需要多个线程来执行运行
		//实例化
		MyThread mt = new MyThread();
		//调用start方法来启动线程
		mt.start();
		//run方法与start方法的区别
//		run方法只是用来封装多线程执行的步骤(代码实现)
//		start是用来开启线程的钥匙
			
		MyThread mt = new MyThread();
		//调用start方法来启动线程
		//设置线程的优先级别   1    5     10
		mt.setPriority(Thread.MIN_PRIORITY);
		mt.start();
		
		MyThread mt2 = new MyThread();
		//调用start方法来启动线程
		mt2.start();
		
	}
}

三、线程的操作
   1. 获取线程的名字

       Thread.currentThread().getName();

   2. 设置线程优先级
    (1)每个线程都有一个优先级;
    (2)高优先级线程的执行优先于低优先级线程;
    (3)每个线程都可以或不可以标记为一个守护程序。
    (4)当某个线程中运行的代码创建一个新 Thread 对象时,该新线程的初始优先级被设定为创建线程的优先级,并且当且仅当创建线程是守护线程时,新线程才是守护程序。
    
    setDaemon(true)
           标识将该线程设置为后台线程,或者叫守护线程,或者叫精灵线程

例:对象.setDaemon(true)

    setPriority()
           设置的优先级一定要足够长时间才会有效果
  

  例:对象.setPriority(Thread.MAX_PRIORITY);  //设置最高级别10
        对象.setPriority(Thread.MIN_PRIORITY);  //最低级别1
        对象.setPriority(Thread.NORM_PRIORITY);  //值为5

    注意:
    (1)设置线程优先级的代码,要放在.start()前面。
    (2)优先级高不一定代表该线程就先抢到执行权,理论是是可以,但实际情况不一样。

四、线程的状态
             

    ||===> 阻塞(临时状态)
                  ||         (有执行资格,没执行权)
                  ||
        start()   ||   sleep(time)
  新建 ========> 运行 =============> 冻结(睡眠|等待)
                  || wait()/notify()
           stop() ||
                  ||
                 消亡(真死了)

1.新建:刚new出来在内存中
2.就绪:start表示该线程有资格抢CPU!
3.运行:抢到了CPU,会执行run方法
4.冻结:放弃了执行资格,醒了获得执行资格,但不一定马上执行。
4.死亡:执行完run方法
5.阻塞:调用了sleep方法或其他阻塞的方法

执行资格与执行权
    ① 没执行资格的情况下,是冻结状态;
    ② 有执行资格的是临时状态;
    ③ 既有执行资格又有执行权的是运行状态。

package javaadvan_07;
/**
 * 下载图片的线程
 * @author Administrator
 *
 */
public class ImgThread extends Thread{
	private String imgPath;
	 public ImgThread(String imgPath) {
		 this.imgPath = imgPath;
	 }

	@Override
	public void run() {
		try {
			WebImageLoader.imgLoad(imgPath);
		} catch (Exception e) {
			
		}
	}		
}


package javaadvan_07;

public class Demo_03 {
	public static void main(String[] args) {
		
		ImgThread it1  = new ImgThread("https://uploadfile.bizhizu.cn/up/7b/60/c7/7b60c7c967c06ab52bc9e2da0f4cbcbc.jpg");
		it1.start();
		ImgThread it2  = new ImgThread("https://pic.3gbizhi.com/2019/1009/20191009011724789.jpg");
		it2.start();
		ImgThread it3  = new ImgThread("https://uploadfile.bizhizu.cn/up/c8/1c/2f/c81c2fe4af5222ff81f81e8f74e2ac26.jpg");
		it3.start();
		
	}
}

五、创建线程的第二种方式:实现Runnable接口
步骤:
    1. 创建类实现Runnable接口; 
    2. 重写Runnable接口中的run()方法;
       将线程要运行的代码存放在该run方法中。
    3. 通过Thread类建立线程对象;
    4. 将Runnable接口的子类对象作为实际参数传递给Thread类的构造方法;
    5. 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

public class Ticket implement Runnable{
private int tick=100;
@override
public void run(){
    while(true){
    if(tick>0){
    System.out.println(Thread.currentThread().getName()+" sale..."+ tick--);
    }
}
}

public class TickDemo{
    public static void main(String[] args){
    Ticket t=new Ticket();  //先实例化一个卖票的对象
    //实例化四个线程
    Thread t1=new Thread(t);  //创建线程
    Thread t2=new Thread(t);
    Thread t3=new Thread(t);
    Thread t4=new Thread(t);
    //让四个线程开始工作
    t1.start();  //执行线程启动run()
    t2.start();
    t3.start();
    t4.start();
    }
}

六、多线程的安全性
1. 问题:
      当多条语句在操作同一个线程共享数据时,一个线程对多条语句时执行了一部分,还没有执行完,另一个线程参与进来执行。导致了共享数据的错误。

2. 解决办法:
      对多条操作共享数据的语句,只能让一个线程执行完。在执行过程中,其他线程不可以参与执行。

Java对于多线程的安全问题提供了专业的解决办法:同步。
          同步分:同步代码块、同步方法

         锁旗标(同步):synchronized

(1) 同步代码块:
    synchronized(对象){  
    //需要被同步的代码
    }
    //表示该段代码上锁

    //如果是代码块后面要放上锁旗标,如果修饰方法,那么它的锁旗标是隐含的this。
(2)锁旗标也可以修饰方法----同步方法。

七、利用线程实现小游戏

老虎机小游戏:

package com.lixiangning.files_07;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class LFJGame extends JFrame{
	  ImageIcon iia=new ImageIcon("image\\1.png");
	  ImageIcon iib=new ImageIcon("image\\2.png");
	  ImageIcon iic=new ImageIcon("image\\3.png");
	  
	  JLabel jla=new JLabel(iia);
	  JLabel jlb=new JLabel(iib);
	  JLabel jlc=new JLabel(iic);
	  JLabel jld=new JLabel(iia);
	  JLabel jle=new JLabel(iib);
	  JLabel jlf=new JLabel(iic);
	  JLabel jlg=new JLabel(iia);
	  JLabel jlh=new JLabel(iib);
	
	
	  JButton jba=new JButton("开始");
	  JButton jbb=new JButton("结束");
	  
	  boolean flag=true;
	  
	  
       public LFJGame() {
    	  this.setTitle("老虎机");
    	  this.setSize(420, 450);
    	  this.setDefaultCloseOperation(3);
    	  this.setLocationRelativeTo(null);
    	  
    	  JPanel jpa=new JPanel();
    	  jpa.setLayout(null);
    	  
    	  jla.setBounds(20, 20, 87, 87);
    	  jpa.add(jla);
    	  
    	  jlb.setBounds(150, 20, 87, 87);
    	  jpa.add(jlb);
    	  
    	  jlc.setBounds(280, 20, 87, 87);
    	  jpa.add(jlc);
    	  
    	  jld.setBounds(20, 150, 87, 87);
    	  jpa.add(jld);
    	  
    	  jle.setBounds(20, 290, 87, 87);
    	  jpa.add(jle);
    	  
    	  jlf.setBounds(150, 290, 87, 87);
    	  jpa.add(jlf);
    	  
    	  jlg.setBounds(280, 150, 87, 87);
    	  jpa.add(jlg);
    	  
    	  jlh.setBounds(280, 290, 87, 87);
    	  jpa.add(jlh);
    	  
    	  
    	  jba.setBounds(115, 170, 70, 30);
    	  jpa.add(jba);
    	  
    	  jbb.setBounds(195, 170, 70, 30);
    	  jpa.add(jbb);
    	  
    	  
    	  jba.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				//1.点击变图
//				int a1= (int) (Math.random()*6+1);
//				int a2= (int) (Math.random()*6+1);
//				int a3= (int) (Math.random()*6+1);
//				
//				iia=new ImageIcon("image\\"+a1+".png");
//				iib=new ImageIcon("image\\"+a2+".png");
//				iic=new ImageIcon("image\\"+a3+".png");
//				
//				jla.setIcon(iia);
//				jlb.setIcon(iib);
//				jlc.setIcon(iic);
				
				
			
				//2.动起来
				flag=true;
				new Thread() {
					public void run() {
						while (flag) {
							
							/*int a1= (int) (Math.random()*6+1);
							int a2= (int) (Math.random()*6+1);
							int a3= (int) (Math.random()*6+1);
							
							iia=new ImageIcon("image\\"+a1+".png");
							iib=new ImageIcon("image\\"+a2+".png");
							iic=new ImageIcon("image\\"+a3+".png");
							
							jla.setIcon(iia);
							jlb.setIcon(iib);
							jlc.setIcon(iic);*/
							//优化代码
							ht(jla,iia);
							ht(jlb,iib);
							ht(jlc,iic);
							ht(jld,iia);
							ht(jle,iib);
							ht(jlf,iic);
							ht(jlg,iia);
							ht(jlh,iib);
							try {
								Thread.sleep(100);
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
					};
				}.start();
				
				
				
			}
		});
    	  
    	 
    	  //结束
    	  jbb.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				flag=false;
			}
		});
    	  
    	  this.getContentPane().add(jpa);
    	  this.setVisible(true);  
       }
       
       //换图
       public void ht(JLabel jl,ImageIcon ii) {
    	   int a1= (int) (Math.random()*6+1);
    	   ii=new ImageIcon("image\\"+a1+".png");
    	   jl.setIcon(ii);
       }
     
       public static void main(String[] args) {
		new LFJGame();
	}
}

 飞天猪小游戏:

package com.lixiangning.files_07;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class ZhuZhu extends JFrame{

	private JPanel jpa = new JPanel(null);
	
	private ImageIcon image = new ImageIcon("image\\bj.gif");
	private JLabel jla = new JLabel(image);
	
	private ImageIcon imb = new ImageIcon("image\\zz.gif");
	private JLabel jlb = new JLabel(imb);
	
	private JLabel jlc = new JLabel(new ImageIcon("image\\zd.gif"));
	
	public ZhuZhu() {
		this.setTitle("");
		this.setSize(820,320);
		this.setDefaultCloseOperation(3);
		this.setLocationRelativeTo(null);
		jla.setBounds(0, 0,820, 320);
     	jpa.add(jla);
		
		
		jlb.setBounds(670,160,96,96);
		jla.add(jlb);
		
		jlc.setBounds(680, 180, 78, 78);
		jla.add(jlc);
			
		
		this.addKeyListener(new KeyListener() {
			
			@Override
			public void keyTyped(KeyEvent e) {
				char keyChar = e.getKeyChar();
				if(keyChar == 'a') {
					jlb.setLocation(jlb.getX()-10, jlb.getY());
				}else if(keyChar == 'd') {
					jlb.setLocation(jlb.getX()+10, jlb.getY());
				}else if(keyChar == 'w') {
					jlb.setLocation(jlb.getX(), jlb.getY()-10);
				}else if(keyChar == 's') {
					jlb.setLocation(jlb.getX(), jlb.getY()+10);
				}			
				
			}
			
			@Override
			public void keyReleased(KeyEvent e) {

//				System.out.println("按键释压");
			}
			
			@Override
			public void keyPressed(KeyEvent e) {

//				System.out.println("按键获压");
			}
		});	
		this.getContentPane().add(jpa);	
	    this.setVisible(true);
	}
	
	public static void main(String[] args) {
		new ZhuZhu();
	}	
	
}

简单游戏:

package com.lixiangning.files_07;

import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class MyGame extends JFrame{
	
	private JPanel jpa = new JPanel(null);
	
	private JLabel jla = new JLabel(new ImageIcon("image\\1.png"));
	private JLabel jlb = new JLabel(new ImageIcon("image\\2.png"));
	private JLabel jlc = new JLabel(new ImageIcon("image\\3.png"));
	
	boolean f = true;
	
	public MyGame() {
		this.setTitle("游戏机");
		this.setSize(841, 350);
		this.setDefaultCloseOperation(3);
		this.setLocationRelativeTo(null);
		
		jla.setBounds(630, 140, 78, 78);
		jlb.setBounds(20, 140, 78, 78);
		jlc.setBounds(650, 250, 78, 78);
		
		jpa.add(jla);
		jpa.add(jlb);
		jlc.setVisible(false);
		jpa.add(jlc);
		
	
		new Thread() {
			public void run() {
				f = true;
				while(f) {
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					if(jlb.getY()+128 <= 300) {
//						System.out.println(jlb.getY());
						jlb.setLocation(jlb.getX(), jlb.getY()+5);
					}else {
						f = false;
					}
					
				}
			};
		}.start();
		
		if(f == false) {
			new Thread() {
				public void run() {
					while(true) {
						if(jlb.getY()+128 >= 300) {
							jlb.setLocation(jlb.getX(), jlb.getY()-5);
						}
						if(jlb.getY()+128 < 10) {
							f = true;
							break;
						}
					}
				};
			}.start();
		}
		
		
		
		this.addKeyListener(new KeyListener() {
			
			@Override
			public void keyTyped(KeyEvent e) {
				char keyChar = e.getKeyChar();
				if('A' == keyChar) {
//					System.out.println(keyChar);
					//子弹显示
					jlc.setVisible(true);
					new Thread() {
						public void run() {
							while(true) {
								try {
									Thread.sleep(100);
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
								jlc.setLocation(jlc.getX()-10, jlc.getY());
								if(jlc.getX() == jlb.getX()) {
									JOptionPane.showMessageDialog(null, "GAME over");
									break;
								}
							}
						};
					}.start();
				}
			}
			
			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub
				
			}
		});
		
		
		
		this.getContentPane().add(jpa);
		this.setVisible(true);
	}
	public static void main(String[] args) {
		new MyGame();
	}
	
}

简单实现点名器:

package com.lixiangning.files_07;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class DianMingQi extends JFrame {
	
	private JPanel jpa = new JPanel(null);
	private JLabel jla = new JLabel("芝麻馅的汤圆0");
	private JButton jba = new JButton("开始");
	private JButton jbb = new JButton("终止");
	
	private String [] mz = {"芝麻馅的汤圆1","芝麻馅的汤圆2","芝麻馅的汤圆3","芝麻馅的汤圆4","芝麻馅的汤圆5",
			"芝麻馅的汤圆6","芝麻馅的汤圆7","芝麻馅的汤圆8","芝麻馅的汤圆9"};
	
	private boolean flag = true;
	private int timer = 50;
	
	public DianMingQi() {
		this.setTitle("点名器");
		this.setSize(820, 350);
		this.setDefaultCloseOperation(3);
		this.setLocationRelativeTo(null);
		
		
		jla.setBounds(270, 30, 400, 100);
		jla.setFont(new Font("华文楷体", Font.BOLD, 45));
		jpa.add(jla);
		jba.setBounds(290, 180, 100, 50);
		jba.setFont(new Font("华文楷体", Font.BOLD, 27));
		jpa.add(jba);
		jbb.setBounds(430, 180, 100, 50);
		jbb.setFont(new Font("华文楷体", Font.BOLD, 27));
		jpa.add(jbb);
		
		
		

		this.getContentPane().add(jpa);
		
		
		
		jba.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				flag = true;
				new Thread() {
					public void run() {
						while(flag) {
						try {
							Thread.sleep(200);
						} catch (Exception e2) {
							// TODO: handle exception
						}
						Random rd = new Random();
		                int sj = rd.nextInt(9);  	
		                jla.setText(mz[sj]);
		                timer+=5;
						if(timer >= 300) {
							timer = 50;
							break;
						}
						}
						};
				}.start();
			}
		});
		
		jbb.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				flag = false;
			}
		});
		
		
		this.setVisible(true);
	}
	

	public static void main(String[] args) {
		new DianMingQi();
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ning_ning_03

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值