java--线程

 进程:

               一个应用程序就是一个或多个进程

 线程:

              一个进程有一个或者多个进程

    public static void main(String[] args) {
	   while(true);
   }

 

Thread类

所属包: java.long;

构造方法

                  public   Thread();

                  public Thread( String name); //参数是给线程起个名字

                  public Thread (Runnable target); //传入要执行的Runnable对象

                  public Thread(Runnable target , String name) ; //可以同时传入中间“ ,”隔开

静态方法:

                   static Thread currentThread();//获取当前线程 

                   static void sleep(long millis);//休息millis毫秒

     //获取当前线程,执行当前代码的线程
	 Thread c=Thread.currentThread();
	 String name=c.getName();
	 System.out.println(name);

 成员变量:

                    private Runnable target;

成员方法:

                  void strat();//启动线程,执行run方法中代码
                  void  run();//线程执行run中代码

                  void getName();//获取线程名字

                  void  getState();//获取线程状态

       //创建一个子线程
       Thread t =new Thread();
	   //启动线程
	   t.start();
	   t.run();

调度方式:

        抢占式调度:给每个任务分配时间不等

         分时调度:给每个任务分配时间是不均等的

  Runnable接口 

                           public  abstract void run();

       //创建一个Runnable类型对象
	   Runnable r = new Runnable() {
		@Override
		public void run() {
			String name=Thread.currentThread().getName();
			System.out.println(name);
		}
		};
		//把Runnable类型对象,赋值给Thread类的成员变量target
		Thread t = new Thread(r,"线程");
		t.start();
        }

Runnable接口方式和继承Thread类的方式:建议使用Runnable方式 

    a.线程和任务分离,解耦合,提高代码的健壮性;

    b.避免了java单继承的局限性;

    c.线程池里面,只能传入Runnable或者callable类对象,不用new Thread

            每一个线程启动都会有一个栈,各自在各自的栈中执行任务

               线程的开销比一般对象的开销要大

线程安全:

         ArrayList<Integer> arr= new ArrayList<>();
		//通过匿名内部类的方式创建Runnable类型对象
		Runnable ru = new Runnable() {
			public void run() {
				for (int i = 0; i <10000; i++) {
					arr.add(i);
				}	
				System.out.println("=======");
		      }
			};
			new Thread(ru).start();
			new Thread(ru).start();
			Thread.sleep(200);
			System.out.println(arr.size());
	}

第一次结果:

标题

第二次结果:

标题

      算出结果应为20000个,结果却不是20000个,所以出现数据丢失问题

解决线程数据丢失问题(上锁):整个的操作不不是原子操作

1.使用synchronized代码块

          语法:

                 synchronized(锁对象){//可以是任意类型的对象

                 //写有可能发生线程安全问题的代码

                 }

     static int n = 0;
	public static void main(String[] args) throws InterruptedException {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10000; i++) {
					synchronized (this) {
						n++;
					}
				}
			}
		};
		new Thread(r).start();
		new Thread(r).start();
		
		Thread.sleep(3000);
		System.out.println(n);
	}
标题

2.使用synchronized方法

            静态synchronized方法:在static和返回值之间加synchronized关键字

            非静态synchronized方法:在返回值之前加synchronized关键字

             synchronized代码块和方法:代码执行完毕后,自动释放锁

    static int n = 0;
	public static void main(String[] args) throws InterruptedException {
		Object obj = new Object();
		
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10000; i++) {
					//调用synchronized方法
					add();
				}
			}
		};
		
		
		new Thread(r).start();
		new Thread(r).start();
		
		Thread.sleep(3000);
		System.out.println(n);
	}
	
	public static synchronized void add() {
		n++;
	}

标题

3.使用Lock锁

             Lock接口:

                             void lock();//上锁

                             void unlock();//开锁

            常用实现类:    ReentrantLock

            构造方法:   public ReentrantLock();

    static int n = 0;
	public static void main(String[] args) throws InterruptedException {
		Lock lock = new ReentrantLock();
		
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10000; i++) {
					//上锁
					lock.lock();
					n++;
					//解锁
					lock.unlock();
				}
			}
		};
		
		
		new Thread(r).start();
		new Thread(r).start();
		
		Thread.sleep(3000);
		System.out.println(n);
	}
	
标题

Java中线程状态:

NEW:新建状态。创建了一个线程,启动之前处于该状态

        Thread t = new Thread();
		State  s = t.getState();
		System.out.println(s);//NEW

RUNNABLE:可运行状态。线程正在执行任务(run方法中的代码),就处于该状态

    Runnable r = new Runnable() {
			@Override
			public void run() {
				for(;;);
			}
		};
		Thread t = new Thread(r);
		t.start();
		
		Thread.sleep(100);//100毫秒保证子线程开始执行Thread.sleep(1000000);这一行代码了
		//获取并打印线程的状态
		System.out.println(t.getState());
	}

BLOCKED:阻塞状态。获取synchronized锁对象失败,就处于该状态

  Runnable r = new Runnable() {
			@Override
			public void run() {
				synchronized(this) {
					for(;;);
				}
			}
		};
		Thread t1 = new Thread(r);
		t1.start();
		Thread t2 = new Thread(r);
		t2.start();
		
		Thread.sleep(100);//100毫秒保证两个子线程已经启动,并开始执行代码了
		//获取并打印线程的状态
		System.out.println(t1.getState());
		System.out.println(t2.getState());
		//获取了锁对象开始执行for循环的线程处于RUNNABLE状态
		//没有获取锁对象的线程处于BLOCKED状态。
	}

WAITING:无限等待状态。获取Lock锁对象失败,就处于该状态

   Lock lock = new ReentrantLock();
		
		Runnable r = new Runnable() {
			@Override
			public void run() {
					lock.lock();
					for(;;);
			}
		};
		Thread t1 = new Thread(r);
		t1.start();
		Thread t2 = new Thread(r);
		t2.start();
		
		Thread.sleep(100);//100毫秒保证两个子线程已经启动,并开始执行代码了
		//获取并打印线程的状态
		System.out.println(t1.getState());
		System.out.println(t2.getState());
		//获取了锁对象开始执行for循环的线程处于RUNNABLE状态
		//没有获取Lock锁对象的线程处于WAITING状态。
	}

TIMED_WAITING:计时等待状态。线程正在执行sleep方法的时候,就处于该状态

   Runnable r = new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(1000000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		Thread t = new Thread(r);
		t.start();
		
		Thread.sleep(100);//100毫秒保证子线程开始执行Thread.sleep(1000000);这一行代码了
		//获取并打印线程的状态
		System.out.println(t.getState());
	}

TERMINATED:消亡状态。线程执行完任务后,就处于该状态

      Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
			}
		};
		Thread t = new Thread(r);
		t.start();
		
		Thread.sleep(1000);//1000毫秒子线程一定把任务执行完毕了
		//获取并打印线程的状态
		System.out.println(t.getState());
	}

线程的通信:线程和线程之间沟通

      等待唤醒机制:  

               object类:

                       void wait();//就会让线程进入等待状态。WAITING状态

                       void wait(long time);//调用该方法,会让线程进入计时等待状态。TIMED_WAITING

                       void notify();//调用该方法,会让线程醒来,接着执行任务。

                       void notifyAll();//调用该方法,会唤醒当前锁对象上等待的所有线程

   注意事项:

                  1.这些方法都必须写在synchronized代码块或者synchronized方法中

                  2.调用这些方法的对象,必须和锁对象一致。

                  3.  t.notify方法,只能唤醒t锁对象上等待的线程

                  4.  调用了wait(不论是否有参数)方法后,会自动释放锁对象。

例子:

1.定义一个Fruit水果类
        成员变量:stock库存
        构造方法、set和get
    2.定义一个官网线程类:NetShop,实现Runnable接口
        完成卖出水果的动作
    3.定义一个实体店线程类:FrontShop,实现Runnable接口
        完成卖出水果的动作
    4.使用等待唤醒机制完成卖出100份坚果的功能
        例如:
            官网正在卖出第1份,还剩余99份
            实体店正在卖出第2份,还剩余98份
            官网正在卖出第3份,还剩余97份
            实体店正在卖出第4份,还剩余96份

实体店:

  public class FrontShop implements Runnable{
	private Fruit f;
	public FrontShop(Fruit f) {
		super();
		this.f = f;
	}

	@Override
	public void run() {
		while(true) {
			synchronized(f) {
				//判断是否退出循环
				if(f.getStock()<=0) {
					break;
				}
				//奇数份,实体店卖
				if(f.getStock()%2==1) {
					//每卖一份,库存减1
					f.setStock(f.getStock()-1);
					System.out.println("实体店正在卖出第"+(100-f.getStock())+"份,还剩 
        余"+f.getStock()+"份");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					//唤醒当前锁对象上等待的线程
					f.notify();
				}else {
					//偶数份,实体店进入等待状态
					try {
						f.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

     官网:

public class NetShop implements Runnable{
	private Fruit f;
	public NetShop(Fruit f) {
		super();
		this.f = f;
	}

	@Override
	public void run() {
		while(true) {
			synchronized(f) {
				//判断是否退出循环
				if(f.getStock()<=0) {
					break;
				}
				//偶数份,官网卖
				if(f.getStock()%2==0) {
					//每卖一份,库存减1
					f.setStock(f.getStock()-1);
					System.out.println("官网正在卖出第"+(100-f.getStock())+"份,还剩余"+f.getStock()+"份");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					//唤醒当前锁对象上等待的线程
					f.notify();
				}else {
					//奇数份,官网进入等待状态
					try {
						f.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}

水果店:

public class Fruit {
	private int stock;
	public int getStock() {
		return stock;
	}
	public void setStock(int stock) {
		this.stock = stock;
	}
	
}

  测试类:

     

public class Test01 {
	public static void main(String[] args) {
		//创建Fruit类型的对象
		Fruit f = new Fruit();
		f.setStock(100);
		
		//创建官网和实体店类型的对象
		Runnable r1 = new NetShop(f);
		Runnable r2 = new FrontShop(f);
		
		//创建两个线程,分别指向这两个任务
		new Thread(r1).start();
		new Thread(r2).start();
	}
}

结果:

 线程池:

1.提高响应速度。预先创建好了线程,只等任务过来执行。

2.降低资源消耗。线程池中的线程,执行完任务后,又返回到线程池中,下一个任务到来后可以继续使用该线程。

3.提高线程的可管理性。一个线程大约需要消耗1M的空间,线程池可以设置最大线程的数量。

Executors类:

                      static ExecutorService newFiexdThredadPool(int nThread);   

ExecutorService接口:

                void execute(Runnable r);//执行任务

                <T> Future<T> submit(Callable<T> c);

                 Future<?> submit(Runnable r);

                  void shutdown();//关闭线程池

     ​Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
			}
		};
		
		//创建一个固定线程池对象
		ExecutorService es = Executors.newFixedThreadPool(2);
		Future<?> future = es.submit(r);
		Object result = future.get();//null
		System.out.println(result);
		//关闭线程池
		es.shutdown();
	}
​

Future<T>接口

                    T get();//必须等子线程把任务执行完成,return以后才可以获取返回的结果

Callable<T>接口:

                     T call();

    Callable<String> c = new Callable<String>() {
			@Override
			public String call() throws Exception {
				//call方法中的代码是某个子线程执行的
				System.out.println(Thread.currentThread().getName());
				return null;
			}
		};
		
		//创建一个固定线程池对象
		ExecutorService es = Executors.newFixedThreadPool(2);
		es.submit(c);
		//关闭线程池
		es.shutdown();
	}

  • 23
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值