Parallel computers and distributed systems are becoming increasingly important. Their impressive computation to cost ratios offer a considerable higher performance than that possible with sequential machines. Yet there are few commercial applications written for them. The reason is that programming in these environments is substantially more difficult than programming for sequential machines. In this thesis, we present Tempo and Tempo++, two programming languages which aim to reduce the inherent complexity of writing concurrent programs. Tempo is a declarative concurrent programming language based on classical first order logic. It improves on traditional concurrent logic programming languages (e.g. Parlog) by explicitly specifying aspects of the behaviour of concurrent programs. In Tempo all safety properties of programs are declaratively stated which provides great advantages in writing concurrent programs and manipulating them while preserving correctness. Concurrent programs in Tempo are developed in such a way that they are not specific to any particular programming paradigm. The language can be used as a common framework for expressing and manipulating algorithms for a variety of paradigms. Tempo++ is a concurrent programming language which extends Tempo by supporting object-oriented programming, and thus, combines most of the features designed in Tempo with the advantages of the object-oriented approach. That is, in Tempo++, concurrency issues are declaratively abstracted by the explicit specification of the safety properties of programs. As in Tempo, this provides great advantages in writing and manipulating programs. Tempo++ applications can be specified as collections of objects, which incorporates a guiding principle for writing programs and introduces the principles of encapsulation and (multiple) inheritance in a logic programming framework. In the language, concurrency issues are separated from the code, minimizing dependency between application functionality and concurrency control. It is, in general, possible to test different synchronisation schemes without modifying the code of the operations, and conversely, a synchronisation scheme may be reused by several applications. Thus, program reuse and program flexibility are increased.