java-单线程基础

进程和线程

  • 进程是动态的程序,特点就是动态。
  • 线程是比进程更小的单位,一个进程可以有一个或多个线程,但是进程最少一个线程。
  • 多线程之间可以分享资源,但是进程之间不会分享资源。
  • 进程是系统资源分配的最小单位,而线程是CPU任务调度。也就是说CPU就是会对多个线程进行分配时间块。

线程的组成部分

  • 时间块:线程必须要得到CPU分配的时间片才可以执行。
  • 共享数据:堆数据可以共享,栈是每个线程独立
  • 线程的逻辑代码

线程的实现方法

方法一:继承Thread类,重写run方法。
缺点就是,java里面是单继承,如果继承了Thread类,那么就不能继承其他类了。

public class MyThread extends Thread{//继承Thread类。
	
	@Override
	public void run() {//重写run方法
		try {
			Thread.sleep(3); //睡眠1毫秒
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		//得到当前进程的名字,currentThread表示当前进程
		String threadName = Thread.currentThread().getName(); 
		
		for(int i = 0 ; i < 100 ; i++) { //循环输出看看输出当前进程的名字和执行次数
			System.out.println(threadName + "==" + i);
		}
	}
}

main方法里面

public static void main(String[] args) {
		
		MyThread my1 = new MyThread();
		my1.start(); //.start()进入是就绪状态,还没获得cpu调度时间,即获得时间块
		
		MyThread my2 = new MyThread();
		my2.start(); 
	}

得到的运行结果那么每次就会都不一样,因为两个对象需要抢位置来获得时间块执行。

方法二:实现Runnable接口,重现run()方法
因为接口,可以实现多个,所以这个优点就是接口的优点实现多继承

public class MyRunnable  implements Runnable{

	@Override
	public void run() {
	}
}
public static void main(String[] args) {
		
		MyRunnable run1 = new MyRunnable(); //就是比继承Thread类多一行代码
		Thread thread1 = new Thread(run1); //这里将对象作为参数传递到进程中
		thread1.start(); //启动进入是就绪状态,还没获得cpu调度时间,即时间块
		//获得当前线程的名称。
		String name = Thread.currentThread().getName();
		for(int i = 0 ; i < 100 ; i++) {
			
			System.out.println(name + "==" + i);
			try {
				my1.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

注意在main方法里面,一定有一个主线程是main,一定有一个主线程是main,一定有一个主线程是main。

从下图的运行结果来看,我没有创建一个线程叫main,一个下面叫Thread-0就是thread1这个对象,在main方法中一定有main线程在这里插入图片描述

线程的状态

这里采用了百度里面的图片,应该来说很贴切。
在这里插入图片描述
初始状态-new关键字
就是创建一个进程对象,进入初始状态。

Thread thread = new Thread;

就绪状态READY-对象.start()

thread.start(); //start并没有进入running 运行中这个状态,只是下一步就是运行中这个状态,这点很重要

运行中状态running-
从上图中可以看到,系统调用,所以这里并没有代码来实现。

等待状态waiting
三种方式实现。

  1. Thread.sleep(毫秒数);
  2. 对象.join(); *//这个会将该对象强行加入到运行状态中,这个有点霸道,但是很重要一点,就绪状态到运行中状态这个谁也说不清,有的时候得到的结果可能不是我们想要的
  3. 对象.wait(); 这个我还没有理解透彻,因为这里需要加上锁。

下面这个例子是Thread.sleep();

public class TestThread {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyThread my1 = new MyThread();
		my1.start(); //启动进入是就绪状态,还没获得cpu调度时间,即执行时间
		
		MyThread my2 = new MyThread();
		my2.start();
	}

}

public class MyThread extends Thread{
	
	@Override
	public void run() {
		try {
			Thread.sleep(3); //睡眠1毫秒
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		String threadName = Thread.currentThread().getName(); 
		//得到当前进程的名字,currentThread表示当前进程
		for(int i = 0 ; i < 100 ; i++) {
			System.out.println(threadName + "==" + i);
		}
	}
}

在这里插入图片描述
阻塞状态

结束状态
也就是线程运行结束。程序结束的话,那么就是main线程结束了。

sleep();yield();join();

这三个方法比较常见吧。
Thread.sleep(毫秒数);表示让当前线程进入等待状态(单位:毫秒),休眠时间到后,会自动进入就绪状态,但是又可以强占时间块。这个有可能产生异常
Thread.yield();表示强行退出时间块,从runnable状态转变成就绪状态,又可以强占时间块。这个不可能产生异常。
对象.join();方法表示对象加入到runnable状态,正在运行的那个对象等待我运行完,你再来。有点强势。

public class TestThread {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyThread my1 = new MyThread();
		my1.start(); //启动进入是就绪状态,还没获得cpu调度时间,即执行时间
		
		MyThread my2 = new MyThread();
		my2.start(); 
		
		//main线程执行
		String main = Thread.currentThread().getName();
		for(int i = 0 ; i < 100 ; i++) {
			
			try {//这个让main线程进入等待状态,那么new的其他对象那么就会先运行。
				Thread.sleep(2);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		System.out.println(main + "==" + i);
		}
	}

}
public class MyThread extends Thread{
	
	@Override
	public void run() {
		try {
			
			Thread.sleep(1);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		String threadName = Thread.currentThread().getName(); 
		//得到当前进程的名字,currentThread表示当前进程
		for(int i = 0 ; i < 100 ; i++) {
			System.out.println(threadName + "==" + i);
		}
	}
}

那么就会先运行my1,my2这两个线程,然后运行main,当然结果有的时候也不是我门像的那样。正常。
Thread.yield();

public class TestThread {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		MyThread my1 = new MyThread();
		my1.start(); //启动进入是就绪状态,还没获得cpu调度时间,即执行时间
		
		MyThread my2 = new MyThread();
		my2.start(); 
		
		//main线程执行
		String main = Thread.currentThread().getName();
		for(int i = 0 ; i < 100 ; i++) {
			
			if(i == 80) {
				Thread.yield();
			}
		System.out.println(main + "==" + i);
		}
	}
}
public class MyThread extends Thread{
	
	@Override
	public void run() {
		try {
			
			Thread.sleep(1);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		String threadName = Thread.currentThread().getName(); 
		//得到当前进程的名字,currentThread表示当前进程
		for(int i = 0 ; i < 100 ; i++) {
			System.out.println(threadName + "==" + i);
		}
	}
}

在这里插入图片描述

到了79的时候,main线程就进入了就绪状态,又要去抢占时间块。

public class TestThread {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		MyThread my1 = new MyThread();
		my1.start(); //启动进入是就绪状态,还没获得cpu调度时间,即执行时间
		
		MyThread my2 = new MyThread();
		my2.start(); 
		
		//main线程执行
		String main = Thread.currentThread().getName();
		for(int i = 0 ; i < 100 ; i++) {
			
			if(i == 80) {
				//Thread.yield();
				my2.join();//那么my2一定能会先执行完毕,除非一种情况,my1,amin之前就已经执行完毕了,没有其他线程进行强占资源。
				my1.join();
			}
		System.out.println(main + "==" + i);
		}
	}
}

改变线程优先级。

方法:对象.setPriority(num); num默认情况是5,num表示的是优先级,num最大只能为10那么优先级就会最大但是也可能出现不是最先进入运行中的状态,num最小只能为1
.`

public class TestThread {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		MyThread my1 = new MyThread();
		my1.start(); //启动进入是就绪状态,还没获得cpu调度时间,即执行时间
		
		MyThread my2 = new MyThread();
		my2.start(); 
		
		my2.setPriority(6); //改变优先级也不一定先执行。
		my1.setPriority(9);
		//main线程执行
		String main = Thread.currentThread().getName();
		for(int i = 0 ; i < 100 ; i++) {
		System.out.println(main + "==" + i);
		}
	}
}

`

线程安全问题

通过加锁的方式来解决,给唯一的对象加锁,要满足两个条件嘛,唯一的以及对象。如果给static方法加锁,那么就是给this加锁;如果給普通方法加锁,锁的就是一般的对象。
加锁是指多个线程同时对一个共享数据进行修改时,先获得修改权限(获取锁)的,会进行加锁(独占),其他的线程会等待(阻塞)当前线程修改完毕后再进行操作。

synchronized加锁就是这个关键字,下面是个普通方法说明了锁this
方法就是
public synchronized void add(){

}

下面这个例子是锁常量,对象,额,这个也不一定对。反正就是要锁不变东西,或者说是对象都要调用的东西。
synchronized (object ,常量){
}

死锁

写程序千万不要造成死锁,因为,这样就会出现很严重的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java多线程基础的答案如下: Java中实现多线程有两种方式,一种是继承Thread类,另一种是实现Runnable接口。其中,实现Runnable接口比继承Thread类更加灵活,因为Java只支持单继承,如果一个类已经继承了其他类,就不能再继承Thread类了。 Java中的线程可以通过调用start()方法来启动,而不是直接调用run()方法。start()方法会在新的线程中执行run()方法。线程可以通过调用sleep()方法来暂停执行一段时间,也可以通过调用join()方法来等待其他线程执行完毕再继续执行。 Java中的线程可以通过synchronized关键字来实现同步,保证多个线程访问共享资源时的安全性。synchronized关键字可以用在方法上或者代码块中,用来锁定对象或者类。 Java中的线程可以通过wait()和notify()方法来实现线程间的通信。wait()方法会使线程进入等待状态,直到其他线程调用notify()方法来唤醒它。notify()方法会随机唤醒一个等待中的线程。 以上就是Java多线程基础的答案。 ### 回答2: Java多线程是Java编程中非常重要的一个方面。多线程是指同时运行多个线程,每个线程都在独立地运行和完成自己的任务。多线程编程是一种高效的编程方式,可以提高程序的运行效率和资源利用率。在Java中,实现多线程的方式有两种:一种是继承Thread类并重写run()方法,另一种是实现Runnable接口并重写run()方法。在使用多线程编程时,需要使用同步机制来避免多个线程同时访问一个共享资源的情况,从而导致数据不一致等问题。关于Java多线程基础,以下是一些注意点和技巧。 一、线程对象的创建 线程对象可以通过继承Thread类或实现Runnable接口来创建。以继承Thread类为例,步骤如下: 1. 定义类并继承Thread类。 2. 重写run()方法。 3. 创建线程对象。 4. 调用线程的start()方法启动线程。 例如: class MyThread extends Thread { public void run() { //执行线程任务 } } MyThread t = new MyThread(); //创建线程对象 t.start(); //启动线程 二、线程的同步和互斥 多个线程同时运行时,可能会访问到同一个共享资源,为了避免数据不一致等问题,需要使用同步机制来限制对共享资源的访问。Java中通过synchronized关键字来实现同步和互斥。synchronized的作用是锁定一个代码块或方法,使得同时只有一个线程能够访问,其他线程需要等待锁释放后才能继续执行。synchronized可以用在关键字方法中,也可以用在代码块中。例如: synchronized void method() { //同步方法 } synchronized(obj) { //同步代码块 } 三、线程的join()方法 join()方法是线程类中的一个重要方法,它的作用是使一个线程等待另一个线程执行完毕后再继续执行。join()方法可以用来协调多个线程的执行顺序。例如: Thread t1 = new Thread(() -> { System.out.println("线程1开始执行"); try { Thread.sleep(1000); //线程1睡眠1秒钟 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1执行结束"); }); Thread t2 = new Thread(() -> { try { t1.join(); //线程2等待线程1执行完毕 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程2开始执行"); }); t1.start(); t2.start(); 四、线程的优先级 线程的优先级可以用来表示线程的重要程度或处理任务的紧急程度。Java中可以通过setPriority()方法设置线程的优先级,优先级分为1~10共10个等级,其中1为最低优先级,10为最高优先级。例如: Thread t = new Thread(); t.setPriority(Thread.MAX_PRIORITY); //设置线程的优先级为最高 五、线程池 线程池是一种常用的线程管理机制,它可以减少线程的创建和销毁过程,提高线程的复用和延迟加载能力。在Java中,可以通过Executor框架来创建和管理线程池。例如: Executor executor = Executors.newFixedThreadPool(10); //创建大小为10的线程池 for (int i = 0; i < 100; i++) { //提交100个任务给线程池执行 executor.execute(() -> { //执行任务 }); } 综上所述,Java多线程是Java编程中非常重要的一个方面。多线程编程可以提高程序的运行效率和资源利用率,但同时也需要注意线程的同步和互斥,协调多个线程的执行顺序,以及线程的优先级和线程池的使用等。 ### 回答3: java多线程是Java中非常重要的知识点,也是编写高并发程序的基础。eduCoder 的头歌中,继承Thread类,实现Runnable接口,使用synchronized关键字等内容都是java多线程的基础知识点。 首先,继承Thread类可以实现多线程编程,因为Java中每一个线程都要有一个Thread对象来代表它,而继承Thread类可以让我们自定义一个线程类。 其次,实现Runnable接口也是实现多线程编程的一种方式。相比于继承Thread类,实现Runnable接口可以让我们更好地管理线程资源,因为一个Java程序中可以创建的线程数量是有限的,使用实现Runnable接口的方式可以更好地利用资源。 接着,synchronized关键字用于保护临界资源,防止多个线程同时访问造成数据的不一致性。在多线程编程中,由于线程的执行顺序和时间不确定,同一时刻可能会有多个线程访问同一个变量或对象,使用synchronized关键字就可以实现线程之间的同步,使得每个线程都可以有序地访问共享资源。 除此之外,还有wait()、notify()、notifyAll()等方法也是实现多线程编程必不可少的工具,它们可以用来实现线程之间的协作。 总之,掌握java多线程的基础知识点不仅可以提高程序的并发性和效率,还能让我们更好地理解Java语言的内部机制,为学习高级多线程编程打下坚实的基础

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值