在说多线程之前,首先要清楚为啥要提出多线程,这就要明白线程和进程间的区别了。

线程和进程间的区别

  进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
  线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
  一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行,相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
  进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,然而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。多个线程共享内存,从而极大地提高了程序的运行效率。

Java线程的生命周期

Java线程的生命周期分为如下几种:

  新建:创建线程对象
  就绪:拥有执行资格,但是没有执行权
  运行:有执行资格且有执行权
  阻塞:没有执行资格和执行权,但是可以被激活到就绪
  死亡:线程对象变为垃圾,等待被回收。

如何创建Java线程

  在Java中,可以通过继承Thread类或者实现Runnable接口来定义一个线程类,于此同时,要重写run方法。当然在继承Thread的时候由于Thread有run方法的默认实现,所以不重写就是执行父类Thread的run方法,实现Runnable必须要重写run方法。另外,之所以定义run方法,是为了申明只有run方法中的代码才会被线程执行,下面就是最简单的定义线程类的例子:

  

public class MyThread extends Thread {
@Override
public void run() {
System.out.println("test Thread!");
}
}
public class RunnableTest implements Runnable {

    @Override
public void run() {
System.out.println("Test Runnable");
}
}

两类线程的启动方式有点区别,如下代码所示:

public class ThreadTest {
public static void main(String args[]) {
MyThread myThread = new MyThread();
myThread.start(); MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start(); }
}

可以看出,实现Runnable的线程类的启动方式是包在Thread的构造方法中,然后还是调用Thread的start方法启动。

如何选择那种实现方式

  在实际定义线程类时,到底选那种,这个时候就需要对比下两者的区别了。Thread的是一个类,其中该类实现了Runnable接口,从类和接口的区别可以看出,继承Thread类就会有单继承的局限;另外,从启动线程来看,继承Thread的类需要每次都new一个对象然后启动,而同一个实现Runnable的线程类可以包在多个Thread构造方法中去启动多线程,这样利于线程间的数据共享。总结起来就是:

  1. Runnable能避免点继承的局限,一个类可以继承多个接口。
  2. Runnable适合于资源的共享

  结论是:开发中一般都多用实现Runnable这种方式,第一避免单继承局限,第二利于数据共享。

 

线程构造方法和重要方法的介绍

由于Runnable是一个接口,并且该接口定义了一个run方法,且该run方法都会被重写,所以只讲解Thread类的构造方法和重要方法,首先来看构造方法:

Thread()
分配新的 Thread 对象。
Thread(Runnable target)
分配新的 Thread 对象。
Thread(Runnable target, String name)
分配新的 Thread 对象。
Thread(String name)
分配新的 Thread 对象。
Thread(ThreadGroup group, Runnable target)
分配新的 Thread 对象。
Thread(ThreadGroup group, Runnable target, String name)
分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,并作为 group 所引用的线程组的一员。
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,作为 group 所引用的线程组的一员,并具有指定的堆栈大小。
Thread(ThreadGroup group, String name)
分配新的 Thread 对象。

  从上述构造方法可以看出,可以通过构造方法设置Thread对象的名字,同时还能设置线程对象的线程组和堆栈大小等。下面是几个重要的方法:

static Thread    currentThread()
返回对当前正在执行的线程对象的引用。
long getId()
返回该线程的标识符。
String getName()
返回该线程的名称。
int getPriority()
返回线程的优先级。
Thread.State getState()
返回该线程的状态。
ThreadGroup getThreadGroup()
返回该线程所属的线程组。
void interrupt()
中断线程。
static boolean interrupted()
测试当前线程是否已经中断。
boolean isAlive()
测试线程是否处于活动状态。
boolean isDaemon()
测试该线程是否为守护线程。
boolean isInterrupted()
测试线程是否已经中断。
void join()
等待该线程终止。
void join(long millis)
等待该线程终止的时间最长为 millis 毫秒。
void setDaemon(boolean on)
将该线程标记为守护线程或用户线程。
void setName(String name)
改变线程名称,使之与参数 name 相同。
void setPriority(int newPriority)
更改线程的优先级。
static void sleep(long millis)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
static void yield()
暂停当前正在执行的线程对象,并执行其他线程。
  • currentThread,getName,getID 方法

下面来测试每个方法,在前面谈线程和进程的关系中谈到一个线程可以启动和撤销另外的线程。在启动两种类型的线程中,说明还有一个背后的线程在启动这两个线程,那这个线程是谁呢?我们可以通过以上的前3个方法得知一二:

public class ThreadTest {
public static void main(String args[]) {
String threadName = Thread.currentThread().getName();
long threadID = Thread.currentThread().getId(); System.out.println(threadID+ ": " + threadName);
}
} //1: main

从结果看出,这是1号线程main线程。那么既然可以获取线程的名字,那么我们也可以手动设置线程的名字,如下测试代码:

package cn.Thread;

/**
* Created by lili on 15/12/6.
*/
public class ThreadTest {
public static void main(String args[]) {
MyRunnable myRunnable = new MyRunnable();
Thread t1 = new Thread(myRunnable);
Thread t2 = new Thread(myRunnable);
t1.setName("Thread1");
t2.setName("Thread2");
t1.start();
t2.start();
} } class MyRunnable implements Runnable { @Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+": "+ i);
}
} }

运行结果则如下:

Thread1: 0
Thread1: 1
Thread1: 2
Thread1: 3
Thread1: 4
Thread1: 5
Thread1: 6
Thread1: 7
Thread1: 8
Thread1: 9
Thread2: 0
Thread2: 1
Thread2: 2
Thread2: 3
Thread2: 4
Thread2: 5
Thread2: 6
Thread2: 7
Thread2: 8
Thread2: 9
  • join方法
package cn.Thread;

/**
* Created by lili on 15/12/6.
*/
public class ThreadTest {
public static void main(String args[]) {
MyRunnable myRunnable = new MyRunnable();
MyRunnable1 myRunnable1 = new MyRunnable1();
Thread t1 = new Thread(myRunnable1);
Thread t2 = new Thread(myRunnable);
Thread t3 = new Thread(myRunnable);
Thread t4 = new Thread(myRunnable); t1.setName("Thread1");
t2.setName("Thread2");
t3.setName("Thread3");
t4.setName("Thread4");
t3.setPriority(Thread.MAX_PRIORITY);
t4.start();
t1.start();
t2.start();
System.out.println("当前活动线程的个数:" + Thread.activeCount());
System.out.println(Thread.getAllStackTraces());
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
} t3.start(); for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} } class MyRunnable implements Runnable { @Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} } class MyRunnable1 implements Runnable { @Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} } class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

  为了获得join的效果,将join线程的循环次数设置的最小,循环次数为5,后启动的3号线程设置最高的优先权。

  在代码中,启动1,2,4后,打印active线程的个数为5,然后再打印stackTrace,这时候main,1,2,4号线程已经是active状态。最终的运行结果是t1,t2,t4先交替抢得执行权执行,待join线程1结束后,剩余线程交替执行。其中在执行t1.join()之前,main线程其实已经启动了,但是main线程最终是等到1执行完毕才开始执行。另外,后启动的t3是等线程1结束了才开始执行。所以从代码执行结果可以看出,join的作用是:

  1. 让主线程等待join子线程执行结束再继续执行;
  2. 让join线程之后启动的线程也等待join线程执行结束再启动执行。

  基于上述两个结论,join 的用法也比较明显,join可以让后续代码获得利用join线程的执行结果。

main: 0
Thread3: 0
Thread3: 1
Thread2: 6
Thread4: 6
main: 1
main: 2
Thread4: 7
Thread2: 7
Thread3: 2
Thread2: 8
Thread4: 8
main: 3
Thread3: 3
Thread4: 9
main: 4
Thread2: 9
Thread3: 4
Thread4: 10
Thread2: 10
Thread3: 5
main: 5
Thread4: 11
Thread2: 11
main: 6
Thread3: 6
Thread4: 12
Thread3: 7
Thread2: 12
main: 7
Thread4: 13
Thread3: 8
main: 8
Thread2: 13
Thread3: 9
Thread2: 14
Thread4: 14
main: 9
Thread3: 10
Thread4: 15
main: 10
Thread2: 15
Thread3: 11
Thread4: 16
Thread2: 16
main: 11
Thread4: 17
main: 12
Thread2: 17
Thread3: 12
Thread4: 18
Thread2: 18
main: 13
Thread3: 13
Thread4: 19
main: 14
Thread2: 19
Thread3: 14
Thread4: 20
main: 15
Thread2: 20
Thread3: 15
Thread2: 21
main: 16
Thread4: 21
Thread3: 16
Thread2: 22
main: 17
Thread3: 17
Thread4: 22
Thread2: 23
main: 18
Thread4: 23
Thread3: 18
Thread2: 24
main: 19
Thread4: 24
Thread3: 19
Thread2: 25
main: 20
Thread3: 20
Thread4: 25
Thread2: 26
main: 21
Thread4: 26
Thread3: 21
Thread2: 27
main: 22
Thread4: 27
Thread3: 22
main: 23
Thread2: 28
Thread4: 28
Thread3: 23
main: 24
Thread2: 29
Thread4: 29
Thread3: 24
main: 25
Thread2: 30
Thread4: 30
Thread3: 25
Thread2: 31
main: 26
Thread4: 31
Thread3: 26
Thread2: 32
main: 27
Thread4: 32
Thread3: 27
Thread2: 33
main: 28
Thread4: 33
Thread3: 28
Thread2: 34
main: 29
Thread4: 34
Thread3: 29
Thread2: 35
Thread4: 35
main: 30
Thread3: 30
Thread2: 36
Thread4: 36
main: 31
Thread3: 31
main: 32
Thread2: 37
Thread4: 37
Thread3: 32
main: 33
Thread2: 38
Thread4: 38
Thread3: 33
Thread2: 39
main: 34
Thread4: 39
Thread3: 34
main: 35
Thread2: 40
Thread4: 40
Thread3: 35
main: 36
Thread2: 41
Thread4: 41
Thread3: 36
Thread2: 42
main: 37
Thread4: 42
Thread3: 37
Thread2: 43
main: 38
Thread4: 43
Thread3: 38
Thread2: 44
main: 39
Thread4: 44
Thread3: 39
Thread2: 45
main: 40
Thread4: 45
Thread3: 40
main: 41
Thread2: 46
Thread4: 46
Thread3: 41
main: 42
Thread4: 47
Thread2: 47
Thread3: 42
main: 43
Thread4: 48
Thread2: 48
Thread3: 43
main: 44
Thread2: 49
Thread4: 49
Thread3: 44
main: 45
Thread2: 50
Thread4: 50
Thread3: 45
main: 46
Thread2: 51
Thread4: 51
Thread3: 46
main: 47
Thread2: 52
Thread4: 52
main: 48
Thread4: 53
Thread2: 53
Thread3: 47
Thread4: 54
Thread3: 48
main: 49
Thread2: 54
Thread3: 49
Thread2: 55
main: 50
Thread4: 55
Thread2: 56
Thread3: 50
main: 51
Thread4: 56
Thread2: 57
main: 52
Thread4: 57
Thread3: 51
Thread3: 52
main: 53
Thread4: 58
Thread2: 58
main: 54
Thread2: 59
Thread4: 59
Thread3: 53
main: 55
Thread2: 60
Thread3: 54
Thread4: 60
Thread4: 61
Thread2: 61
main: 56
Thread3: 55
main: 57
Thread2: 62
Thread4: 62
Thread3: 56
Thread4: 63
main: 58
Thread2: 63
Thread3: 57
main: 59
Thread4: 64
Thread2: 64
Thread3: 58
main: 60
Thread4: 65
Thread2: 65
Thread3: 59
main: 61
Thread4: 66
Thread2: 66
Thread3: 60
main: 62
Thread4: 67
Thread2: 67
Thread3: 61
main: 63
Thread4: 68
Thread2: 68
Thread3: 62
main: 64
Thread4: 69
Thread2: 69
Thread3: 63
Thread4: 70
main: 65
Thread2: 70
Thread3: 64
main: 66
Thread4: 71
Thread2: 71
Thread3: 65
main: 67
Thread4: 72
Thread2: 72
Thread3: 66
Thread4: 73
main: 68
Thread2: 73
Thread3: 67
Thread4: 74
main: 69
Thread2: 74
Thread3: 68
main: 70
Thread4: 75
Thread3: 69
Thread2: 75
Thread4: 76
main: 71
Thread3: 70
Thread2: 76
Thread4: 77
main: 72
Thread3: 71
Thread2: 77
main: 73
Thread4: 78
Thread2: 78
Thread3: 72
main: 74
Thread4: 79
Thread2: 79
Thread3: 73
Thread4: 80
main: 75
Thread2: 80
Thread3: 74
main: 76
Thread4: 81
Thread2: 81
Thread3: 75
main: 77
Thread4: 82
Thread2: 82
Thread3: 76
main: 78
Thread4: 83
Thread2: 83
Thread3: 77
Thread4: 84
main: 79
Thread2: 84
Thread3: 78
Thread4: 85
main: 80
Thread2: 85
Thread3: 79
Thread4: 86
main: 81
Thread2: 86
Thread3: 80
Thread4: 87
main: 82
Thread2: 87
Thread3: 81
Thread4: 88
main: 83
Thread2: 88
Thread3: 82
Thread4: 89
main: 84
Thread2: 89
Thread3: 83
main: 85
Thread4: 90
Thread2: 90
Thread3: 84
Thread4: 91
main: 86
Thread2: 91
Thread3: 85
Thread4: 92
main: 87
Thread2: 92
Thread3: 86
Thread4: 93
main: 88
Thread2: 93
Thread3: 87
Thread4: 94
main: 89
Thread2: 94
Thread4: 95
Thread3: 88
main: 90
Thread2: 95
Thread4: 96
main: 91
Thread3: 89
Thread2: 96
Thread4: 97
main: 92
Thread3: 90
Thread4: 98
Thread2: 97
main: 93
Thread3: 91
Thread2: 98
Thread4: 99
main: 94
Thread3: 92
Thread2: 99
main: 95
Thread3: 93
main: 96
Thread3: 94
main: 97
Thread3: 95
main: 98
Thread3: 96
main: 99
Thread3: 97
Thread3: 98
Thread3: 99

view join result

  • setDaemon方法

  将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。当传入参数为true时则表示设置该线程为守护线程。守护线程的应用场景多用在后台管理,业务逻辑不应该封装在守护线程中,不然结果不稳定。

  • interrupt方法

   该方法的作用在于中断线程,线程中断后,将不在执行。

  • yield()方法

  yield方法是一种礼让方法,意思就是让出cpu执行权给其他线程,例如下属代码最后的效果就是Thread1和Thread2交替执行,因为双方都在执行一次后让出执行权。

public class ThreadTest {
public static void main(String args[]) {
MyRunnable myRunnable = new MyRunnable(); Thread t1 = new Thread(myRunnable);
Thread t2 = new Thread(myRunnable); t1.setName("Thread1");
t2.setName("Thread2"); t1.start();
t2.start(); } } class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
Thread.yield();
}
} }

线程安全问题

  多线程的好处在于效率高,但是很多人都怕用多线程,因为觉得多线程会有安全问题,这里要说的是多线程并不一定是不安全的,如果有数据共享,才会存在安全问题,如果完全不存在数据共享,相互独立的执行,这是不会存在安全问题的。那在有数据共享的情况下(Runnable实现情况下一般都是有数据共享的),如何保证线程执行的安全性呢?

  用synchronized同步控制来保证安全。synchronized可以用来修饰代码块和方法,synchronized同步控制相当于对框起来的代码加了一把锁,每个线程只有拿到这把锁才能进入使用操作代码。

多线程实现购票用例

public class ThreadTest {
public static void main(String args[]) {
MyRunnable myRunnable = new MyRunnable(40); Thread t1 = new Thread(myRunnable);
Thread t2 = new Thread(myRunnable);
Thread t3 = new Thread(myRunnable); t1.setName("售票口1");
t2.setName("售票口2");
t3.setName("售票口3"); t1.start();
t2.start();
t3.start();
}
} class MyRunnable implements Runnable {
private int tickets; public MyRunnable(int tickets) {
this.tickets = tickets;
} @Override
public void run() {
sellTickets();
// while (true) {
// synchronized (this) {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// if (tickets > 0) {
// System.out.println(Thread.currentThread().getName() + "正在出售第: " + tickets-- + " 张票");
// }
// }
// }
} public synchronized void sellTickets(){
while (true) {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第: " + tickets-- + " 张票");
}
}
}
} }

JDK5新特性Lock

利用synchronized对于在哪里开始加锁了哪里释放了锁不够明显,JDK5提供的新特性Lock可以明确加锁和释放锁的位置。如下代码测试:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class ThreadTest {
public static void main(String args[]) {
MyRunnable myRunnable = new MyRunnable(40); Thread t1 = new Thread(myRunnable);
Thread t2 = new Thread(myRunnable);
Thread t3 = new Thread(myRunnable); t1.setName("售票口1");
t2.setName("售票口2");
t3.setName("售票口3"); t1.start();
t2.start();
t3.start();
}
} class MyRunnable implements Runnable {
private int tickets;
private Lock lock = new ReentrantLock(); public MyRunnable(int tickets) {
this.tickets = tickets;
} @Override
public void run() {
while (true) {
try {
lock.lock();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第: " + tickets-- + " 张票");
}
} finally {
lock.unlock();//为了防止代码出错锁不能解除的情况
} }
}
}

【Java基础】Java多线程小结的更多相关文章

  1. Java基础技术多线程与并发面试【笔记】

    Java基础技术多线程与并发 什么是线程死锁? ​死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去,我们就可以称 ...

  2. java基础---->java中正则表达式二

    跟正则表达式相关的类有:Pattern.Matcher和String.今天我们就开始Java中正则表达式的学习. Pattern和Matcher的理解 一.正则表达式的使用方法 一般推荐使用的方式如下 ...

  3. Java基础-Java中的堆内存和离堆内存机制

    Java基础-Java中的堆内存和离堆内存机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.

  4. Java基础-Java中的内存分配与回收机制

    Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二.

  5. Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock)

    Java基础-Java中的并法库之重入读写锁(ReentrantReadWriteLock) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在学习Java的之前,你可能已经听说过读 ...

  6. Java基础-Java中的并法库之线程池技术

    Java基础-Java中的并法库之线程池技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是线程池技术 二.

  7. Java基础-Java中23种设计模式之常用的设计模式

    Java基础-Java中23种设计模式之常用的设计模式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   一.设计模式分类 设计模式是针对特定场景给出的专家级的解决方案.总的来说设 ...

  8. Java基础-JAVA中常见的数据结构介绍

    Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...

  9. Java基础-Java数据类型

    Java基础-Java数据类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.数据类型的作用 数据类型就是一组值,以及这一组值上的操作,数据类型可以决定数据的存储方式,取值范围 ...

  10. Java基础之多线程篇(线程创建与终止、互斥、通信、本地变量)

    线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...

随机推荐

  1. 一次Oracle数据迁移

    目标数据库:Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 源数据库  : Oracle Database 11g Enterpri ...

  2. opengl混合效果

    效果如下图:

  3. 关于2440的裸跑程序中SD卡读后不能成功写入问题的讨论

    问题描述: TQ2440的官方裸跑程序中,对SD卡先进行读操作,然后再写,发现不能程序卡死.倘若对SD卡先写后读,程序可以正常运行,奇哉怪哉? 写数据的关键代码--> while(i < ...

  4. <四> SQL存储过程

    存储过程的定义: create procedure procedurename @param1 nvarchar(30) as select * from tablename where name = ...

  5. Microsoft Visual Studio 2010 Service Pack 1(exe)

    在线安装包:https://cid-3ca83445bd7767a0.office.live.com/browse.aspx/.Public/VS2010 ISO:http://download.mi ...

  6. CSS3学习之 animation 属性

    发现animation这个新属性很有趣,在此学习,并整理下!  浏览器支持: Internet Explorer 10.Firefox 以及 Opera 支持 animation 属性: Safari ...

  7. android打造万能的适配器(转)

    荒废了两天,今天与大家分享一个ListView的适配器 前段时间在学习慕课网的视频,觉得这种实现方式较好,便记录了下来,最近的项目中也使用了多次,节省了大量的代码,特此拿来与大家分享一下. 还是先看图 ...

  8. android开发之---文字居中---android中去掉标题栏

    1. 让textView里面的内容水平居中 :    android:gravity="center_horizontal" 2. 让textView控件在它的父布局里水平居中   ...

  9. [JavaScript] js获取Html元素的实际宽度高度

    第一种情况就是宽高都写在样式表里,就比如#div1{width:120px;}.这中情况通 过#div1.style.width拿不到宽度,而通过#div1.offsetWidth才可以获取到宽度. ...

  10. POJ3714+最近点对

    特判标记即可 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h& ...