Java学习札记之线程


一、进程和线程概念
我的理解,简单地说:进程,就是一个正在执行的程序,那我们知道,一个进程有许许多多的模块组成,比如,把我们人比做一个进程,我们人体有八大系统在周而复始的运转,如果哪个除了问题,那人就生病了,那这八个系统下又有许许多多的组织在独立运转,凡此种种,共同维系着人体正常的机能运转;线程呢,简单的说就是进程的一个组成单元。想这个例子,把人比作一个进程,那么八大系统就可以比作组成人这个进程的八个子模块——线程。
人家比较专业的说法:
进程:是一个正在执行中的程序 。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元
线程:就是进程中的一个独立的控制单元。 线程在控制着进程的执行。
要明确一点的是:进程是由线程组成的,那么自然一个进程中至少有一个线程。

联系我们的Java程序,每个java程序都有一个main方法,其实就是一个线程啦。Java VM 启动的时候会有一个进程叫做java.exe,该进程中至少有一个线程在负责java程序的执行,而且这个线程运行的代码存在于main方法中。该线程称之为主线程。


       其实更细节说明虚拟机JVM,JVM启动不止一个线程,还有负责垃圾回收机制的线程,好像是什么gc机制,个人不是怎么很了解,反正好像就是说,你内存中的一些东东,一段时不要,就会把你自动清理掉。


二、如何创建线程
Java API提供了专门针对线程这类事物的描述,就是类Thread和接口Runnable
创建方式一:操作Thread
1、继承Thread类;
2、覆盖Thread中的run()方法;
目的:将自定义的代码存储在run()方法中,让线程运行。
3、创建并启动一个线程,即调用线程的start()方法,start()方法有两个作用,启动线程,调用run方法。
创建方式二:实现Runnable接口
1、定义类实现Runnable接口;
2、覆盖Runnable接口中的run方法,将线程要运行的代码存放在该run()方法中;
3、通过Thread类建立线程对象;
4、通过Thread接口的子类对象作为实际阐述传递给Thread类的构造函数。那这里不是很清楚,为什么要将Runnable接口的子类对象传递给Thread的构造函数?是因为,自定义的run方法所属的对象的Runnable接口的子类对象,所以要让线程去指定指定对象的run方法,就必须要明确该run方法所属的对象。
5、最后一步,就是调用Thread类的start方法开启并调用Runnable接口子类的run方法。


二者之间的区别?
实现方式的好处:避免了单继承的局限性,在定义线程时,建议使用实现接口的方式。
继承Thread线程代码存放Thread子类run方法中;
实现Runnable,线程代码存放在子类的run方法中。 但这两个区别,我觉得说了等于没说。。。


三、示例说明
继承Thread方式: 例子很简单,就不说明了
class Demo extends Thread
{
	public void run()
	{
		for(int x = 0 ; x < 60 ; x++)
			System.out.println("demo run--- " + x);
	}
}
class  ThreadDemo
{
	public static void main(String[] args) 
	{
		Demo d = new Demo();
		//d.start();


		for(int x = 0 ; x < 60 ; x++)
			System.out.println("Hello World!==== " + x);


		Thread t = new Thread(d);
		t.start();


	}
}
Runnable方式:例子很简单
class Ticket implements Runnable //extends Thread
{
	private int tick = 20;
	public void run()
	{
		while(true)
		{


			if(tick > 0)
			{
				System.out.println(Thread.currentThread().getName() + " sale : " + tick--);
			}
		}
	}


}




class  TicketDemo
{
	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();
		t2.start();
		t3.start();
		t4.start();


		/*
		Ticket t1 = new Ticket();
		Ticket t2 = new Ticket();
		Ticket t3 = new Ticket();
		Ticket t4 = new Ticket();


		t1.start();
		t2.start();
		t3.start();
		t4.start();
		*/
	}
}




四、线程同步
对于同步的理解,不知道怎么说好,但我觉得最简单的理解就是: 给我等着,别着急,等我上完厕所,你再上。。
百事不决问百度,百度上这么说:同步就是协同步调,按预定的先后次序进行运行。“同”字从字面上容易理解为一起动作;其实不是,“同”字应是指协同、协助、互相配合。如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。
当然,从上面的描述中,可以感觉到,需要线程同步的必须是两个线程以上,不然又怎么谈: 给我等着,别着急,等我上完厕所,你再上 。。。对吧?
那在我们Java程序中如何体现呢?
举个小例子:


/*
需求:
银行有一个金库
有两个储户分别存300元,每次存100

目的:改程序是否有安全问题,如果哟,如何解决?

如何
1、明确哪些代码是多线程运行代码。
2、明确共性数据。
3、明确多想运行代码中哪些语句是操作共享数据的。

同步有两种表现方式 :同步函数和同步代码块
*/

class Bank
{
	private int sum;
	public synchronized void add(int n)
	{
		//synchronized(this)
	//	{
			sum = sum + n;
		//	try{Thread.sleep(10);}catch(Exception e){}
			System.out.println("sum = " + sum);
	//	}
	}
}
class Cun implements Runnable
{
	private Bank b = new Bank();
	public void run()
	{
		for(int x = 0 ; x < 3 ; x++)
		{
			b.add(100);
		}
	}
}
class  BankDemo
{
	public static void main(String[] args) 
	{
		Cun c = new Cun();
		Thread t1 = new Thread(c);
		Thread t2 = new Thread(c);


		t1.start();
		t2.start();
	}
}



说明:注释的语句,就是用了同步代码块而不是同步函数解决问题的。
同步也有弊端,死锁,我不恨明白,但是我基本的理解就是很死循环不能说想,至少有那么一丁点共同之处,程序卡在那个地方不动了。


五、单例模式
接下来,毕老师讲了一下什么叫单利模式,确实也是第一次听说,觉得蛮新鲜的。从网上找了一些介绍:
单利设计模式,解决一个类在内存中只存在一个对象。

想要保证对象唯一:
1、为了避免其他程序过多建立该类对象,先避免其他程序建立该类对象;
2、为了其他程序可以访问到该对象,只好在奔雷中,自定义一个对象。
3、为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
代码的思想:
1、将构造方法私有化
2、在类中创建一个本类对象;
3、提供一个方法方便自个在其他程序可以获取对象

举例说明:

//饿汉式
/*
class Single
{
	private static final Single s = new Single();
	private Single(){};
	public static Single getInstance()
	{
		return s;
	}
}
*/


//懒汉式
//特点时延时加载
//懒汉式在多线程访问时存在安全问题
//不过懒汉式加上同步判断会比较低效
//用双重否定可以解决效率问题
//同步代码块的对象,类名.class


class Single
{
	private static Single s = null;
	private Single(){}
	public static Single getInstance()
	{
		if(s==null)
		{
			synchronized(Single.class)
			{
				if(s == null)
				{
					s = new Single();
				}
			}
		}
		return s;
	}
}


class  SingleDemo
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
}



针对他们的设计,在开发中常用饿汉式,安全性较高,可以保证,该对象时存在的,先懒汉式有可能会爆出对象不存在,空指针的异常,因为如果要在线程中需要这些对象时,在上面代码有可能对象还没被创建就去执行其他的语句,造成程序公职真挂掉,所以大家都在用饿汉式,饿汉式就不会出现这种状况,管你之不执行,在你之前不管三七二十一我先创建了再说,管你以后用不用,呵呵。
今天就写到这了,明天放假了,调整一
下继续啊,吾生也有涯,学也无涯。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值