线程 浅析
要想了解线程先明白进程的概念,进程:可以把它简单理解成一个应用程序员.而线程:则是进程的一个单元片段,多个线程组成了一个进程。同理,多线程则是有多条通路可以执行我
们的程序,它提高了我们程序的效率。它在启动时启动了两个线程,一个非守护线程(main线程)第二个(守护线程)垃圾回收线程。
java是面向对象的语言,java中的线程不是面向对象的。它的处理线程操作时,与c相比它的缺点很明显。创建线程之前需要导包,但java.lang包,对于这个包下的所有的类在使用时不需要导包的。
包名java.lang.Thread类就是java中的线程类,java中的线程优先级一共有10个,默认的是5 最高的是10,最低的是1。
java创建线程有两种方式——1,将我们自己的类声明成Thread类的子类,继承Thread类(extends Thread)
步骤1.将当前类继承自Thread类2.重写父类中的run方法3.启动线程,调用Thread类中的start方法
2.声明自己的类实现Runnable接口.(implements Runnable)步骤1.创建一个类实现Runnable接口2.将接口中的run方法重写3.启动线程,调用Thread类中的 start方法.下面是代码。
class Demo1
{
public static void main(String[] args)
{
ThreadDemo demo1=new ThreadDemo(); //创建一个线程
ThreadDemo demo2=new ThreadDemo(); //创建另外一个线程
demo1.start();//启动线程1
demo2.start();//启动线程2
System.out.println(demo1.id);
System.out.println(demo2.id);
}
}
class ThreadDemo extends Thread
{
int id=10; //成员变量,每个对象中都有
public void run(){
id++;
}
}
2.声明自己的类实现Runnable接口,实现Runnable接口,(implements Runnable)
步骤 1.创建一个类实现Runnable接口
2.将接口中的run方法重写
3.启动线程 调用Thread类中的start方法
class Demo2
{
public static void main(String[] args)
{
ThreadDemo demo=new ThreadDemo();
//创建一个线程,并启动
new Thread(demo).start();
//创建另一个线程,并启动
new Thread(demo).start();
System.out.println(demo.id);
System.out.println(demo.id);
}
}
class ThreadDemo implements Runnable
{
int id=10; //成员变量,每个对象中都有
public void run(){
id++;
}
}
java中线程的执行具有无序性,多个线程在执行时,它的执行顺序是由cpu时间片来分配的,这个我们是控制不了的,它的执行结果会产生无序性。
那么,在实际开发中我们选择哪一种方式去创建线程?首选应当是接口,原因有:1.使用接口可以让我们程序扩展性更强,一个类只能继承一个父类,但是可以实现多个接口。2. 使用extends Thread类是要想多个线程操作公共数据,那么这个数据要是static,如果不是static,而是实例属性,那么代表的是每个线程操作的都是自己的属性。static属性的缺点:它的生命周期太长,所占用的内存一直得不到释放.使用implements Runnable接口时,多个线程在操作公共数据时这个属性可以是实例属性,因为只有一个实现了Runnable接口的对象,要想创建线程并启动它,是通过new Thread(Runnable runnable)这样的方式去创建线程对象的。
同步线程(线程安全),线程安全问题产生的原因:多个线程通过多条语句去操作共享数据。如何解决线程的安全问题?当某一个线程在操作数据时,它没有操作完,其它的线程是不允许操作的。只有当这个线程执行完成后,我们才允许其它线程操作。我们管这种机制叫锁的机制。
对于线程同步的问题,两种解决方式——1.使用synchronized 块。2.使用synchronized 方法
使用同步代码块解决安全问题注意事项:所有的线程在操作时,要保证线程是案例的,必须保证所使用的锁是同一个.
同步方法,其时就是使用synchronized去修饰一个方法.
同步代码块与同步方法的原理是一样的,区别在于它们所控制的范围不一样。同步方法它是将整个方法都锁定。线程没有执行完这个方法,其它线程是不能执行的。而同步代码块我们可以控制只方法中的某一部分去锁。在实际操作中建议使用同步代码块。
class Demo3 //同步代码块演示
{
public static void main(String[] args)
{
ThreadDemo demo=new ThreadDemo();
new Thread(demo).start();
new Thread(demo).start();
}
}
class ThreadDemo implements Runnable
{
int id=10;
Object obj=new Object();
public void run(){
synchronized(obj){ //这种情况代表所有的线程在使用时所使用的锁对象是同一个。这样才能解决安全问题.
id++;
try{
Thread.sleep(1);
}catch(Exception e){
}
System.out.println(id);
}
System.out.println("同步代码块");
}
}
同步方法它其时也是使用同步代码块实现的。那么同步方法它所使用的锁是什么?非静态的同步方法所使用的锁对象就是this,静态的同步方法所使用的锁对象不是this,当前静态同步方法所使用的锁对象就是线程类的.class文件对象。
java中的所有的类都有一个静态的属性叫做.class,它的作用是得到当前类的字节码对象.
class Demo4 //同步方法演示
{
public static void main(String[] args)
{
ThreadDemo demo=new ThreadDemo();
new Thread(demo).start();
new Thread(demo).start();
}
}
class ThreadDemo implements Runnable
{
int id=10;
public void run(){
show();
}
public synchronized void show(){
id++;
try{
Thread.sleep(1);
}catch(Exception e){
}
System.out.println(id);
System.out.println("同步方法");
}
}
多个线程互相持有对方锁时会产生死锁,怎样避免产生死锁?死锁一般出现的原因就是嵌套问题,很容易出现死锁。要想避免产生死锁,那么就尽量少去嵌套。
下面是死锁的举例。
class Test1 {
public static void main(String[] args) {
DeadLock d = new DeadLock();
new Thread(d).start();
new Thread(d).start();
}
}
class DeadLock implements Runnable{
Object obj = new Object();
boolean flag = true;
public void run() {
while (true) {
if (flag) {
flag = false;
show1();
} else {
flag = true;
synchronized(obj) {
/*
try {
Thread.sleep(1);
}
catch (Exception e) {
}*/
show2();
}
}
}
}
public synchronized void show1() {
/*
try {
Thread.sleep(1);
} catch (Exception e) {
}*/
synchronized(obj) {
System.out.println("show1....");
}
}
public void show2() {
synchronized(this) {
System.out.println("show2....");
}
}
}
要想了解线程先明白进程的概念,进程:可以把它简单理解成一个应用程序员.而线程:则是进程的一个单元片段,多个线程组成了一个进程。同理,多线程则是有多条通路可以执行我
们的程序,它提高了我们程序的效率。它在启动时启动了两个线程,一个非守护线程(main线程)第二个(守护线程)垃圾回收线程。
java是面向对象的语言,java中的线程不是面向对象的。它的处理线程操作时,与c相比它的缺点很明显。创建线程之前需要导包,但java.lang包,对于这个包下的所有的类在使用时不需要导包的。
包名java.lang.Thread类就是java中的线程类,java中的线程优先级一共有10个,默认的是5 最高的是10,最低的是1。
java创建线程有两种方式——1,将我们自己的类声明成Thread类的子类,继承Thread类(extends Thread)
步骤1.将当前类继承自Thread类2.重写父类中的run方法3.启动线程,调用Thread类中的start方法
2.声明自己的类实现Runnable接口.(implements Runnable)步骤1.创建一个类实现Runnable接口2.将接口中的run方法重写3.启动线程,调用Thread类中的 start方法.下面是代码。
class Demo1
{
public static void main(String[] args)
{
ThreadDemo demo1=new ThreadDemo(); //创建一个线程
ThreadDemo demo2=new ThreadDemo(); //创建另外一个线程
demo1.start();//启动线程1
demo2.start();//启动线程2
System.out.println(demo1.id);
System.out.println(demo2.id);
}
}
class ThreadDemo extends Thread
{
int id=10; //成员变量,每个对象中都有
public void run(){
id++;
}
}
2.声明自己的类实现Runnable接口,实现Runnable接口,(implements Runnable)
步骤 1.创建一个类实现Runnable接口
2.将接口中的run方法重写
3.启动线程 调用Thread类中的start方法
class Demo2
{
public static void main(String[] args)
{
ThreadDemo demo=new ThreadDemo();
//创建一个线程,并启动
new Thread(demo).start();
//创建另一个线程,并启动
new Thread(demo).start();
System.out.println(demo.id);
System.out.println(demo.id);
}
}
class ThreadDemo implements Runnable
{
int id=10; //成员变量,每个对象中都有
public void run(){
id++;
}
}
java中线程的执行具有无序性,多个线程在执行时,它的执行顺序是由cpu时间片来分配的,这个我们是控制不了的,它的执行结果会产生无序性。
那么,在实际开发中我们选择哪一种方式去创建线程?首选应当是接口,原因有:1.使用接口可以让我们程序扩展性更强,一个类只能继承一个父类,但是可以实现多个接口。2. 使用extends Thread类是要想多个线程操作公共数据,那么这个数据要是static,如果不是static,而是实例属性,那么代表的是每个线程操作的都是自己的属性。static属性的缺点:它的生命周期太长,所占用的内存一直得不到释放.使用implements Runnable接口时,多个线程在操作公共数据时这个属性可以是实例属性,因为只有一个实现了Runnable接口的对象,要想创建线程并启动它,是通过new Thread(Runnable runnable)这样的方式去创建线程对象的。
同步线程(线程安全),线程安全问题产生的原因:多个线程通过多条语句去操作共享数据。如何解决线程的安全问题?当某一个线程在操作数据时,它没有操作完,其它的线程是不允许操作的。只有当这个线程执行完成后,我们才允许其它线程操作。我们管这种机制叫锁的机制。
对于线程同步的问题,两种解决方式——1.使用synchronized 块。2.使用synchronized 方法
使用同步代码块解决安全问题注意事项:所有的线程在操作时,要保证线程是案例的,必须保证所使用的锁是同一个.
同步方法,其时就是使用synchronized去修饰一个方法.
同步代码块与同步方法的原理是一样的,区别在于它们所控制的范围不一样。同步方法它是将整个方法都锁定。线程没有执行完这个方法,其它线程是不能执行的。而同步代码块我们可以控制只方法中的某一部分去锁。在实际操作中建议使用同步代码块。
class Demo3 //同步代码块演示
{
public static void main(String[] args)
{
ThreadDemo demo=new ThreadDemo();
new Thread(demo).start();
new Thread(demo).start();
}
}
class ThreadDemo implements Runnable
{
int id=10;
Object obj=new Object();
public void run(){
synchronized(obj){ //这种情况代表所有的线程在使用时所使用的锁对象是同一个。这样才能解决安全问题.
id++;
try{
Thread.sleep(1);
}catch(Exception e){
}
System.out.println(id);
}
System.out.println("同步代码块");
}
}
同步方法它其时也是使用同步代码块实现的。那么同步方法它所使用的锁是什么?非静态的同步方法所使用的锁对象就是this,静态的同步方法所使用的锁对象不是this,当前静态同步方法所使用的锁对象就是线程类的.class文件对象。
java中的所有的类都有一个静态的属性叫做.class,它的作用是得到当前类的字节码对象.
class Demo4 //同步方法演示
{
public static void main(String[] args)
{
ThreadDemo demo=new ThreadDemo();
new Thread(demo).start();
new Thread(demo).start();
}
}
class ThreadDemo implements Runnable
{
int id=10;
public void run(){
show();
}
public synchronized void show(){
id++;
try{
Thread.sleep(1);
}catch(Exception e){
}
System.out.println(id);
System.out.println("同步方法");
}
}
多个线程互相持有对方锁时会产生死锁,怎样避免产生死锁?死锁一般出现的原因就是嵌套问题,很容易出现死锁。要想避免产生死锁,那么就尽量少去嵌套。
下面是死锁的举例。
class Test1 {
public static void main(String[] args) {
DeadLock d = new DeadLock();
new Thread(d).start();
new Thread(d).start();
}
}
class DeadLock implements Runnable{
Object obj = new Object();
boolean flag = true;
public void run() {
while (true) {
if (flag) {
flag = false;
show1();
} else {
flag = true;
synchronized(obj) {
/*
try {
Thread.sleep(1);
}
catch (Exception e) {
}*/
show2();
}
}
}
}
public synchronized void show1() {
/*
try {
Thread.sleep(1);
} catch (Exception e) {
}*/
synchronized(obj) {
System.out.println("show1....");
}
}
public void show2() {
synchronized(this) {
System.out.println("show2....");
}
}
}