Java线程--上

Java线程

进程:

在计算机中正在运行的任务
一边看电影一边聊QQ微信
现在大部分的计算机都支持多任务模式
CPU在某个时间点上只能做一件事
CPU计算能力非常强,计算的速度太快了,让我们感觉都是同时在运行的

线程:

线程基于进程而存在
一个进程中一般会有多个线程
多个线程共享当前进程的内容空间和系统资源
每个线程想执行都得抢占CPU资源,抢占的可能性随机的
main方法运行本身就会启动一个线程--主线程

标题Thread的方法:

void start() 
          使该线程开始执行;Java 虚拟机调用该线程的 run 方法 
Thread(String name) 
          分配新的 Thread 对象。
Thread(Runnable target) 
          分配新的 Thread 对象。
Thread(Runnable target, String name) 
          分配新的 Thread 对象并指定线程名称。
String getName() 
          返回该线程的名称。 
static Thread currentThread() 
          返回对当前正在执行的线程对象的引用。 
static void sleep(long millis) 
          程序执行到sleep方法,就根据指定的时间来暂停当前线程运行;当时间结束时恢复运行;
void setName(String name) 
      改变线程名称,使之与参数 name 相同。

自定义线程:

三种方式:

		方式一:
				步骤:
					1、自定义类继承Thread
					2、重写run方法,run方法中定义的是当前要执行的内容
					3、创建线程的对象
					4、调用对象start方法来启动线程
/**
 * 自定义线程方式一
 */
public class ThreadDemo1 {
    public static void main(String[] args) throws InterruptedException {
        //创建线程对象
        Mythread mythread = new Mythread("线程1");
        //启动线程
        mythread.start();
        //mythread.start();//一个线程不能启动多次
        Mythread mythread1 = new Mythread("线程2");
        mythread1.start();
        /*for (int i=0;i<=10;i++){
            Thread.sleep(100);//加sleep方便体现多线程,暂停100秒
            System.out.println(Thread.currentThread().getName()+":"+i);
        }*/
    }
}
//自定义mythread继承thread
class Mythread extends Thread{
    public Mythread(String name){
        super(name);
    }
    //重写run方法
    @Override
    public void run(){
        //循环打印数字
        for (int i=0;i<=10;i++){
            try {
                Thread.sleep(100);//加sleep方便体现多线程,暂停100秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName()+":"+i);
        }
    }
}

run方法和start方法有什么区别?
run方法:线程执行的代码逻辑
start:直接调用启动线程
如果直接调用线程的run方法,并不是启动新的线程,而是在原来的线程中调用执行run方法
如何启动一个线程?
调用start方法,当线程启动之后,JAVA虚拟机会去调用线程重写的run方法

方式二:
		步骤:
				1、自定义类实现Runnable接口
				2、实现run方法
				3、创建线程类的对象,该对象身上没有start方法,所以需要创建Thread类的对象,将自定义的线程对象作为参数传入
				4、调用对象start方法来启动线程
/**
 * 自定义线程方式二
 */
public class ThreadDemo2 {
    public static void main(String[] args) {
    //创建对象
    Mythread1 my1 = new Mythread1();
    //创建Thread类对象
    Thread thread1 = new Thread(my1);
    //调用start方法启动线程
        thread1.start();
    }
}
class Mythread1 implements Runnable{
//实现run方法
    @Override
    public void run() {
        for (int i=0;i<=10;i++){
            System.out.println("run:"+i);
        }
    }
}

方式三:
步骤:
1、自定义类实现Callable接口
2、实现call方法
3、从线程池获取一个服务对象(ExecutorService ec = Executors.newCachedThreadpool)
4、调用对象的submit方法,把自定义的线程类对象作为参数传入,返回值存储到Future对象中
5、打印返回值

练习:
春节买火车票,有三个窗口同时售票:
某趟车只剩100张票,当三个窗口加起来已经买了100张票之后不再运行
方式一:

/**
 * 方式一
 * 三个窗口同时售票
 */
public class TicketDemo {
    public static void main(String[] args) {
        SellTicket thread = new SellTicket();
        SellTicket thread1 = new SellTicket();
        SellTicket thread2 = new SellTicket();
        thread.setName("窗口一");
        thread1.setName("窗口二");
        thread2.setName("窗口三");
        //启动线程
        thread.start();
        thread1.start();
        thread2.start();
    }
}
class SellTicket extends Thread{
    private static int ticket = 100;
    @Override
    public void run(){
        while (ticket>0){
            System.out.println(Thread.currentThread().getName()+"当前正在卖第:"+ticket+"张票");
            ticket--;
        }
    }
}

方式二:

	package cn.ppenggs.test;
/**
 * 方式二
 * 三个窗口同时售票
 */
public class TicketDemo2 {
    public static void main(String[] args) {
        SellTicket1 st1 = new SellTicket1();//只创建一次对象
        new Thread(st1,"窗口一").start();
        new Thread(st1,"窗口二").start();
        new Thread(st1,"窗口三").start();
    }
}
class SellTicket1 implements Runnable{
    private  int ticket = 100;//可以不用static,只创建一次对象
    @Override
    public void run(){
        while (ticket>0){
            System.out.println(Thread.currentThread().getName()+"当前正在卖第:"+ticket+"张票");
            ticket--;
        }
    }
}

一般推荐使用方式二----实现Runnable

注意:多线程并发安全问题:

	1、每个线程每时每刻都在尝试抢占CPU资源
	  		为什么会出现多线程安全问题?
	  					(1):多线程
	  					(2):多个线程共享同一数据资源
	  					(3):共享数据被多行代码使用
	  		怎么解决多线程安全问题?
	  				针对问题3,可以通过同步锁机制来解决这个问题
	  						(1):同步代码块
	  								格式:
	  										synchronized(锁对象){
	  												此处代码块会被锁起来
	  										}
	  										锁对象:必须得所有线程都认识;要求对所有线程
/**
 * 同步代码块
 */
public class TicketDemo2 {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        ticket.setNum(100);
        SellTicket1 st1 = new SellTicket1(ticket);//只创建一次对象
        new Thread(st1,"窗口一").start();
        new Thread(st1,"窗口二").start();
        new Thread(st1,"窗口三").start();
    }
}
class SellTicket1 implements Runnable{
    private Ticket ticket;
    public SellTicket1(Ticket ticket){
        this.ticket = ticket;
    }

    @Override
    public void run(){
        while (true){
            try {
                Thread.sleep(100);//方便查看,效果明显
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (ticket){
        if (ticket.getNum()>0) {
            System.out.println(Thread.currentThread().getName() + "当前正在卖第:" + ticket.getNum() + "张票");
            ticket.setNum(ticket.getNum()-1);
        }
            }
        }
    }
}
//Ticket单独定义类创建对象作为锁对象
class Ticket{
    private int num;
    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
}

(2):同步方法
格式:
在方法定义上加上synchronized关键字
锁对象是this

			package cn.tedu.thread.exer;
		
		public class TicketDemo2 {
		    public static void main(String[] args) {
		        Ticket ticket = new Ticket();
		        ticket.setNum(100);
		        SellTicket2 st1 = new SellTicket2(ticket);
		        new Thread(st1,"窗口1").start();
		        new Thread(st1,"窗口2").start();
		        new Thread(st1,"窗口3").start();
		    }
		}
		
		class SellTicket2 implements Runnable{
		    private Ticket ticket;
		    public SellTicket2(Ticket ticket){
		        this.ticket = ticket;
		    }
		    @Override
		    public void run() {
		        while(true){
		            try {
		                Thread.sleep(10);
		            } catch (InterruptedException e) {
		                e.printStackTrace();
		            }
		          sell();          
		        }
		    }
		    public synchronized void sell(){
		            if(ticket.getNum()>0){
		                try {
		                    Thread.sleep(10);
		                } catch (InterruptedException e) {
		                    e.printStackTrace();
		                }
		                System.out.println(Thread.currentThread().getName()+"当前正在卖第"+ticket.getNum()+"张票");
		                ticket.setNum(ticket.getNum()-1);
		            }
		    }
		}
		class Ticket{
		    private int num;
		
		    public int getNum() {
		        return num;
		    }
		
		    public void setNum(int num) {
		        this.num = num;
		    }
		}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值