java多线程的总结

java多线程中:有三种方式创建线程

1.继承Thread()

public class ThreadClass extends Thread{

	private String name;
	public ThreadClass(){}
	public ThreadClass(String name)             
	{
		this.name=name;
	}
	
	 public  void run()  
	   {  
	        System.out.println(name);  
	   }  
	 
	 
	 public static void main(String str[])
	 {
		 
		 ThreadClass tc=new ThreadClass("我是继承Thread创建的线程");
		 tc.start();
	 }
}


2.实现Runnable接口创建

public class MyThread implements Runnable{

	 
		private String name;
		public MyThread(){}
		public MyThread(String name)             
		{
			this.name=name;
		}
		
		@Override
		public void run() {
			 System.out.println(name);  
			
		}

	 public static void main(String str[])
	 {
		 
		 Runnable tc=new MyThread("我是实现Runnable创建的线程");
		 Thread mt=new Thread(tc);
		 mt.start();
		 
	 }
}

优点是Runnable到处可以复用。


3.最省事的创建,也是基于Runnable的

Thread t= new Thread(new Runnable(){

		@Override
		public void run() {}});          
t.start();



2:创建完了,我们来使用。

首先看下常用的几个API:

sleep();                    //  调用方式:       线程.sleep(时间);           代表线程休息多少秒后,再加入争抢;  主线程休息的话是:Thread.sleep(1000)   表示主线程休息1000毫秒

join();                     //运用场景:比如现在要上传10张图片,这10张图片放在多个子线程中上传,我们必须得让子线程上传完整后在通知父线程做接下来的工作,因此join()就发挥了作用了。直接上例子:

线程1:
public class MyThread implements Runnable{
				
		@Override
		public void run() {
			
			for(int i=0;i<100;i++)
			{
			System.out.print(i+" ");
			
			}
		}
}

线程2:
public class MyThread1 implements  Runnable{
	public MyThread1()
	{}
			
	@Override
	public void run() {
		
		for(int i=0;i<100;i++)
		{
			System.out.print(i+" ");
		
		}
	}
}

测试:
public class TestExample {

	public static void main(String args[]) throws InterruptedException
	{
		
		Runnable one=new MyThread();
		Thread t=new Thread(one);
		
		Runnable two=new MyThread1();
		Thread t2=new Thread(two);
		
		t.start();
		t2.start();
		t.join();               //t执行完才到主线程
		t2.join();             //t2执行完猜到主线程
		Thread.sleep(5000);   //主线程先休息500毫秒先
		System.out.print("到我执行了");
	}

}

结果:两个子线程执行完后才到主线程。



第二部分线程安全,数据安全的问题:

先来看个不安全的情况:直接上代码:

数据不安全:
public class TestnoThread {
	private static int sum=500;
	 public static void main(String[] args) throws Exception {   


	Thread t= new Thread(new Runnable(){

		@Override
		public void run() {
			 
			while(sum>0)
			{
				
				
				 System.out.print("t1="+sum+" ");
				 System.out.print("我是T1");
				 System.out.println();
				 sum--;
				
				 }
			
			
		}});
	
	Thread t2= new Thread(new Runnable(){

		@Override
		public void run() {
			
			while(sum>0)
			{
				 System.out.print("t2="+sum+" ");
				 System.out.print("我是T2");
				 System.out.println();
				 sum--;
				
			 
			}
		}});
	Thread.sleep(1000);
	t.start();
	t2.start();	 
	 }   
}

测试的结果:

t1=500 t2=500 我是T2
t2=499 我是T2
t2=498 我是T2
t2=497 我是T2
t2=496 我是T2
t2=495 我是T2
t2=494 我是T2
t2=493 我是T2
t2=492 我是T2
t2=491 我是T2
t2=490 我是T2

500被打印了两次,这就是数据不安全了;


如何解决呢:

让500按顺序来打印:  这时需要引入  3个重要的API

第一: synchronized()                     

第二: sumtwo.notify();              通知那些调用了 sumtwo.wait()的线程加入争抢中。

第三: sumtwo.wait();                 中断sumtwo线程,需要sumtwo.notify()的唤醒。


让500按顺序打印,不重复打印,也不缺少,两个线程打印:主要控制sum自减不出现差错就可以了,所以一个信号量可以搞定;下面是例子

public class TestThwo {
	private static int sum=500;
	 private static Object sigh=new Object();
	 public static void main(String[] args) throws Exception {   

	Thread t= new Thread(new Runnable(){

		@Override
		public void run() {
			 
			while(sum>0)
			{
				synchronized(sigh)
				{
				
				 System.out.print("t1="+sum+" ");
				 System.out.print("我是T1");
				 System.out.println();
				 sum--;
				
				 }
			}
			
		}});
	
	Thread t2= new Thread(new Runnable(){

		@Override
		public void run() {
			
			while(sum>0)
			{
				synchronized(sigh)
				{
				 System.out.print("t2="+sum+" ");
				 System.out.print("我是T2");
				 System.out.println();
				 sum--;
				}
			 
			}
		}});
	Thread.sleep(1000);
	t.start();
	t2.start();	 
	 }   
}

下面是结果:

t1=500 我是T1
t1=499 我是T1
t1=498 我是T1
t1=497 我是T1
t1=496 我是T1
t1=495 我是T1
t1=494 我是T1
t1=493 我是T1
t1=492 我是T1
t1=491 我是T1
t1=490 我是T1
t1=489 我是T1
t1=488 我是T1
t1=487 我是T1
。。。。。
t1=443 我是T1
t2=442 我是T2
t2=441 我是T2
t2=440 我是T2
t2=439 我是T2
t2=438 我是T2


其实看代码:我们可以发现就是多了一个控制自减所要用到的信号量,和一个控制信号量的东东synchronized(sigh)

 private static Object sigh=new Object();

synchronized(sigh)


我们继续改进:让T1和T2轮流从500顺序打印:首先得控制自减,这是一个信号量,其次,得控制顺序,这又是一个信号量,因此总共需要2个信号量:

直接代码献上:

public class TestXhThread {

	private static Integer  sum=200;

	private static Object sums=new Object();        //信号量1
	private static Object sumtwo=new Object();      //信号量2
	

	 public static void main(String[] args) throws Exception {   

	Thread t= new Thread(new Runnable(){

		@Override
		public void run() {
			 
			while(sum>0)
			{
				 synchronized(sumtwo) {
				 synchronized(sums) { 
				
				 System.out.print("t1="+sum+" ");
				 System.out.print("我是T1");
				 System.out.println();
				 sum--;
				 sums.notify();          //去通知线程2
				 }
				try {
					sumtwo.wait();       //中断线程,等到其他线程使用sumtwo.notify出现的时候,线程被唤醒
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				 }
				}
			}
		}});
	
	Thread t2= new Thread(new Runnable(){

		@Override
		public void run() {
			
			while(sum>0)
			{
				 synchronized(sums)
				 {
				 synchronized(sumtwo) { 
					
				 System.out.print("t2="+sum+" ");
				 System.out.print("我是T2");
				 System.out.println();
				 sum--;
				sumtwo.notify();          //去通知线程1
				 }
				try {
					sums.wait();
				} catch (InterruptedException e) {
					
					e.printStackTrace();
				}
				 }
			 
			}
		}});
	Thread.sleep(1000);
	t.start();
	t2.start();

	 }   

}

效果图:

t2=200 我是T2
t1=199 我是T1
t2=198 我是T2
t1=197 我是T1
t2=196 我是T2
t1=195 我是T1
t2=194 我是T2
t1=193 我是T1
t2=192 我是T2

最后附上收藏了一个控制三个变量循环打印的例子:网上看到的,感觉理解了它很多线程问题都可以解决了。

public class ThreadAbc implements Runnable{

	private String name;
	private Object prev;
	private Object selt;
	
	

	public ThreadAbc(String name, Object prev, Object selt) {
		super();
		this.name = name;
		this.prev = prev;
		this.selt = selt;
	}





	@Override
	public void run() {
		 int count = 10;   
	        while (count > 0) {   
	            synchronized (prev) {   
	                synchronized (selt) {   
	                    System.out.print(name);   
	                    count--;  
	                    selt.notify();     //设防自身所,唤醒下一个等待的进程
	                }   
	                try {   
	                    prev.wait();   //释放前一个锁,终止当前线程
	                } catch (InterruptedException e) {   
	                    e.printStackTrace();   
	                }   
	            }   
	  

	}
	}
	
	
	
	
	 public static void main(String[] args) throws Exception {   
	        Object a = new Object();   
	        Object b = new Object();   
	        Object c = new Object();   
	      ThreadAbc pa = new ThreadAbc("A", c, a);   
	      ThreadAbc pb = new ThreadAbc("B", a, b);   
	      ThreadAbc pc = new ThreadAbc("C", b, c);   
	           
	           
	        new Thread(pa).start();
	        Thread.sleep(100);  //确保按顺序A、B、C执行
	        new Thread(pb).start();
	        Thread.sleep(100);  
	        new Thread(pc).start();   
	        Thread.sleep(100);  

	 }

}


//线程池与自造线程的资源损耗和效率:

线程池(推荐)

线程池:
public static void main(String[] args) throws IOException, InterruptedException {
			long start = System.currentTimeMillis();
			
			 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(9);  
			 
			  for ( int i = 0; i <100; i++) {  
			  
			   fixedThreadPool.execute(new suotu(i));
					     
					     }
			  fixedThreadPool.shutdown();
			  while(true)
			  {
				  if (fixedThreadPool.isTerminated()) {  
		                System.out.println("结束了!");  
		                break;  
		            }  
		            Thread.sleep(200);  
			  }

			  System.out.println(System.currentTimeMillis()-start);
			
		}


一个任务一个线程:消耗资源极大(不推荐)

public static void main(String[] args) throws IOException, InterruptedException {
			long start = System.currentTimeMillis();
			List<Thread>ls=new ArrayList<>();
			
			
			 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(9);  
			 
			  for ( int i = 0; i <200; i++) {  
			  

					     Thread t=new Thread(new suotu(i));
					     ls.add(t);
					     }
			  for(int i=0;i<ls.size();i++)
			  {
				  ls.get(i).start();
				 
			  }
			  for(int i=0;i<ls.size();i++)
			  {
				  ls.get(i).join();
			  
			 }

			  System.out.println(System.currentTimeMillis()-start);
			
		}
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值